循环执行函数时,错误:超出最大存储过程,函数,触发器或视图嵌套级别(限制32)

时间:2014-12-31 02:32:22

标签: 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

我正在尝试填充一个表格(当输入为Prod2时),

1234  Prod2  200 34 12 23

执行以下存储过程时会出现以下错误。

错误:超出了最大存储过程,函数,触发器或视图嵌套级别(限制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

2 个答案:

答案 0 :(得分:0)

您收到的错误消息与递归调用有关。

在您的解决方案中,您没有放置“GO'在' END'之间以及程序的测试执行。 可能性是将测试的执行编译到过程代码本身。

答案 1 :(得分:0)

我将假设此练习的目的是将值拆分出列,以便您可以规范化数据。

  1. 关于实际错误阅读@ Amir的回答
  2. 关于帮助您解决问题,请看下面的方法,希望您可以从中获取一些帮助。
  3. -- 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