Sql server 在函数中循环时,错误:超过了最大存储过程、函数、触发器或视图嵌套级别(限制32)
我是SQL Server 2008的新手。非常感谢您的帮助。如果我写的存储过程是一个耗时的因素,请有人帮我写一个更好的方法Sql server 在函数中循环时,错误:超过了最大存储过程、函数、触发器或视图嵌套级别(限制32),sql-server,tsql,stored-procedures,Sql Server,Tsql,Stored Procedures,我是SQL Server 2008的新手。非常感谢您的帮助。如果我写的存储过程是一个耗时的因素,请有人帮我写一个更好的方法 Table Name: tblProduct Column Names: Product No, S1_CR, S1_CAT1, S1_CAT2, S1_CAT3, S1_CAT4 Eg Column Values: 1234, Prod1#Prod2#Prod3, 10#200#300, 20#34#400, 40#12#12, 50#23#12 我试图填充一个表,该表
Table Name: tblProduct
Column Names: Product No, S1_CR, S1_CAT1, S1_CAT2, S1_CAT3, S1_CAT4
Eg Column Values: 1234, Prod1#Prod2#Prod3, 10#200#300, 20#34#400, 40#12#12, 50#23#12
我试图填充一个表,该表将显示为(当输入为Prod2时)
执行以下存储过程时出现以下错误
错误:超过最大存储过程、函数、触发器或视图嵌套级别(限制32)
存储过程有一个函数(instr),调用该函数可查找字符串中哈希的出现次数,以帮助填充表
存储过程:
Alter Procedure spPopulate
@Code varchar(10),
@Test int,
@Product varchar(10),
@Year varchar(4)
as
Begin
Declare @Pos int
select @Pos = LEN(SUBSTRING(S1_CR, 0, CHARINDEX(@Code, S1_CR, 0))) - LEN(REPLACE(SUBSTRING(S1_CR, 0, CHARINDEX(@Code, S1_CR, 0)), '#' , '')) from tblProduct where Product =@Product and Year = @Year
select ProductNo, s1_cr, s1_cat1, S1_CAT2, S1_CAT3, S1_CAT4,
case
when @Test >= 1 then right(LEFT(s1_CAT1, dbo.INSTR(S1_CAT1+ '#', '#', 1, @Pos+1)-1), (dbo.INSTR(S1_CAT1+ '#', '#', 1, @Pos+1)-1)- (dbo.INSTR(S1_CAT1+ '#', '#', 1, @Pos)+1)+1) end as CAT1,
case
when @Test >= 2 then right(LEFT(s1_CAT2, dbo.INSTR(S1_CAT2+ '#', '#', 1, @Pos+1)-1), (dbo.INSTR(S1_CAT2+ '#', '#', 1, @Pos+1)-1)- (dbo.INSTR(S1_CAT2+ '#', '#', 1, @Pos)+1)+1) end as CAT2,
case
when @Test >= 3 then right(LEFT(s1_CAT3, dbo.INSTR(S1_CAT3+ '#', '#', 1, @Pos+1)-1), (dbo.INSTR(S1_CAT3+ '#', '#', 1, @Pos+1)-1)- (dbo.INSTR(S1_CAT3+ '#', '#', 1, @Pos)+1)+1) end AS CAT3,
case
when @Test >= 4 then right(LEFT(s1_CAT4, dbo.INSTR(S1_CAT4+ '#', '#', 1, @Pos+1)-1), (dbo.INSTR(S1_CAT4+ '#', '#', 1, @Pos+1)-1)- (dbo.INSTR(S1_CAT4+ '#', '#', 1, @Pos)+1)+1) end AS CAT4
from Product where Product=@Product and Year = @Year ;
End
Execute spPopulate @Code = 'Prod1', @Product= 'ProductName1', @Year = '2010', @Test = 1
请在下面找到instr的功能
ALTER FUNCTION [dbo].[INSTR] (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
RETURNS INT
AS
BEGIN
DECLARE @found INT = @occurrence,
@pos INT = @start;
WHILE 1=1
BEGIN
-- Find the next occurrence
SET @pos = CHARINDEX(@substr, @str, @pos);
-- Nothing found
IF @pos IS NULL OR @pos = 0
RETURN @pos;
-- The required occurrence found
IF @found = 1
BREAK;
-- Prepare to find another one occurrence
SET @found = @found - 1;
SET @pos = @pos + 1;
END
RETURN @pos;
END
您收到的错误消息与递归调用有关 在您的解决方案中,您没有将“GO”放在过程的“END”和测试执行之间。
很可能是您将测试的执行编译成了过程代码本身。我将假设此练习的目的是将值从列中分离出来,以便您可以对数据进行标准化
字符串处理通常非常慢……特别是如果您编写了InStr()方法,并且如果应用于所有或多行……您通常可以用LIKEIt替换。看起来正确的解决方案是更好的数据结构。使用散列来分隔值,然后尝试使用查询将其拆分,这与关系数据库的用途背道而驰。您将使用更好的数据结构解决递归错误和速度问题。100%同意@Lathejockey81:Normalise@Lathejockey81 sir/mam,您能建议我如何为该表提供更好的数据结构吗。提前感谢您抽出时间。如果你能给我发消息,我可以在一些网站上找到一些好的数据库设计,这对像meWow这样的新手也会很有帮助。。我必须衷心感谢你的努力和所花的时间。我在执行这部分代码时遇到问题,请您帮助我,否则如果“@”index=0和“@”term_count“@”num_terms和“@”reviewing“@”S1_CR--num_terms在查看第一列时将为零。这是我正在获取的错误-Msg 102,级别15,状态1,第70行“@'num_terms”附近的语法不正确。消息156,级别15,状态1,第72行关键字“else”附近语法不正确。再次感谢。@Katheeja-当我粘贴“对不起”时被删除了。。。替换为“如果'@index=0和'@term\u count'@num\u terms和'@reviewing'@S1\u CR',则需要从变量namesWow.中删除前导单引号。”。。谢谢你。。太好了。上帝保佑你。我会一次又一次地研究代码:-)你可能不理解我这一辈子的兴奋。再次感谢您的时间。如何修改代码以获得与Prod2匹配的所有记录。插入到“@源价值(1234)、源价值(1234)、源价值(1234)、Prod1#;; Prod1#;生产3#生产3#生产3#;生产3#;生产3#生产3#生产3 35;生产3 35;生产3 35;生产4、生产4、生产4、1 3555 355 355#生产4、1、1、1、1 3555 5 5 8 3558 3555 8 3555 535; 8)8 3555 8 8 8 8 35;; 8 3555 5 5 5 5 5 5 5 5 8 8 35;; 8、2、2、2、2、2、2、2、2、2、5、4、3、4、3、4、4、2、1、3、4、3、4、2、1、1、2、2、2、2、2、2、2、2、2、3、3、3、3、4、3、4、3、4、3、4、4、3、4、3、4、4、4、3、5、5、5、5、5、5、4、4、4、4、3、5、5、4、5、5、4、5、4、4、3、3、5、3、5、5、5、5、5、4、5、5、4、5、5、4、4、3、3、3、3、3、5、5、3、5、5、5、5、5、5、5、5、5、5、4、5、5、4、5、5、5、4、5、5、5、4、3、3、3、5、3、5、5、5、5、5#8')我希望最终目的是将所有数据从这种疯狂的格式中解放出来。假设这是所有的历史数据,并且您正在取出并放入一个新表,那么,1。从查询末尾的结果集中删除筛选器,2.按照预期将其放入存储过程中,3。对每个prodID执行一次该过程,4.使用prodID/ProdCode将返回的行存储到新表中以获得唯一性。5.然后,您可以随意查询新表中的所有数据,这将很容易。
ALTER FUNCTION [dbo].[INSTR] (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
RETURNS INT
AS
BEGIN
DECLARE @found INT = @occurrence,
@pos INT = @start;
WHILE 1=1
BEGIN
-- Find the next occurrence
SET @pos = CHARINDEX(@substr, @str, @pos);
-- Nothing found
IF @pos IS NULL OR @pos = 0
RETURN @pos;
-- The required occurrence found
IF @found = 1
BREAK;
-- Prepare to find another one occurrence
SET @found = @found - 1;
SET @pos = @pos + 1;
END
RETURN @pos;
END
-- set up our sample datasource
declare @source as table
(
ProductNo int,
S1_CR varchar(100),
S1_CAT1 varchar(100),
S1_CAT2 varchar(100),
S1_CAT3 varchar(100),
S1_CAT4 varchar(100)
)
insert into @source values (1234, 'Prod1#Prod2#Prod3', '10#200#300', '20#34#400', '40#12#12', '50#23#12')
-- set up what will become input parameters to our sp
declare @prodNo int = 1234
declare @code varchar(10) = 'Prod2'
--Note that there are not Columns named Product, Year in the sample data but you refer to it in your Query so I assume they exist
declare @Product varchar(10) -- is your declaration long enough? calling your sp you use 'ProductName1' which wont fit.
declare @year varchar(4) = '2010'
-- this could be a constant if it doesnt change from record to record,
-- or a parameter if it does
declare @delimiter char = '#'
--declare our variables
declare @output table
(
ProductNo int,
S1_CR varchar(100),
S1_CAT1 varchar(100),
S1_CAT2 varchar(100),
S1_CAT3 varchar(100),
S1_CAT4 varchar(100)
)
declare @ProductNo int
declare @S1_CR varchar(100)
declare @S1_CAT1 varchar(100)
declare @S1_CAT2 varchar(100)
declare @S1_CAT3 varchar(100)
declare @S1_CAT4 varchar(100)
--these ones are used during validation
declare @index int = 1
declare @term_count int = 0 -- this counts the number of terms in the column we are looking at
declare @num_terms int = 0 -- this becomes our fixed comparison value
declare @reviewing varchar(100) -- this is the data from the column we are looking at
select
@ProductNo = s.ProductNo,
@S1_CR = s.S1_CR + @delimiter,
@S1_CAT1 = s.S1_CAT1 + @delimiter,
@S1_CAT2 = s.S1_CAT2 + @delimiter,
@S1_CAT3 = s.S1_CAT3 + @delimiter,
@S1_CAT4 = s.S1_CAT4 + @delimiter
from @source s
where s.ProductNo = @prodNo
set @reviewing = @S1_CR
--validate to ensure there are equal number of concatenated terms in each column
--you will probably want to do other validation on inputs etc.
while @index > 0 --and @num_terms > 0
begin
set @index = CHARINDEX(@delimiter, @reviewing, @index +1)
if @index > 0
set @term_count = @term_count + 1
else if @index = 0 and @term_count @num_terms and @reviewing @S1_CR -- num_terms will be zero when reviewing the first column
set @num_terms = 0
else
begin
select
@num_terms = case @reviewing
when @S1_CR then @term_count
else @num_terms
end,
@reviewing = case @reviewing
when @S1_CR then @S1_CAT1
when @S1_CAT1 then @S1_CAT2
when @S1_CAT2 then @S1_CAT3
when @S1_CAT3 then @S1_CAT4
else ''
end
if @reviewing = ''
set @index = 0
else
set @index = 1
set @term_count = 0
end
end
--Split out the terms
while @num_terms > 0
begin
insert into @output values
(
@ProductNo,
left(@S1_CR,CHARINDEX(@delimiter,@S1_CR,1) -1),
left(@S1_CAT1,CHARINDEX(@delimiter,@S1_CAT1,1) -1),
left(@S1_CAT2,CHARINDEX(@delimiter,@S1_CAT2,1) -1),
left(@S1_CAT3,CHARINDEX(@delimiter,@S1_CAT3,1) -1),
left(@S1_CAT4,CHARINDEX(@delimiter,@S1_CAT4,1) -1)
)
set @S1_CR = right(@S1_CR,len(@S1_CR) - CHARINDEX(@delimiter,@S1_CR,1))
set @S1_CAT1 = right(@S1_CAT1,len(@S1_CAT1) - CHARINDEX(@delimiter,@S1_CAT1,1))
set @S1_CAT2 = right(@S1_CAT2,len(@S1_CAT2) - CHARINDEX(@delimiter,@S1_CAT2,1))
set @S1_CAT3 = right(@S1_CAT3,len(@S1_CAT3) - CHARINDEX(@delimiter,@S1_CAT3,1))
set @S1_CAT4 = right(@S1_CAT4,len(@S1_CAT4) - CHARINDEX(@delimiter,@S1_CAT4,1))
set @num_terms = @num_terms - 1
end
select * from @output where S1_CR = @code