2014-12-31 33 views
1

我是SQL Server 2008的新手。任何幫助都非常感謝。如果我寫的存儲過程是耗時的因素,那麼有人可以幫助我以更好的方式編寫代碼。在循環函數的同時,錯誤:超過了最大存儲過程,函數,觸發器或視圖嵌套級別(限制32)

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 [email protected] 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 [email protected] 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 
+1

字符串處理往往很慢....特別是如果你寫一個InStr函數()方法,如果適用於所有或許多行...你可以經常更換與LIKE –

+3

它看起來像正確的解決方案是一個更好的數據結構。使用散列來分離值,然後嘗試使用查詢拆分它們違背了關係數據庫的目的。您將通過更好的數據結構來解決遞歸錯誤和速度問題。 – Lathejockey81

+0

100%同意@ Lathejockey81:標準化。 –

回答

0

我會假設這個練習的目的是將值從列中分離出來,這樣你就可以規範化你的數據。

  1. 關於閱讀@阿米爾的答案
  2. 關於幫助你解決你的問題,實際的錯誤看看下面我的方法,希望你可以從拉的東西來幫助你。
-- 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 
+0

哇..我必須衷心感謝你花費的努力和時間。如果'@'index = 0和'@'term_count'@'num_terms和'@'複查'@',那麼我在執行這部分代碼時遇到了麻煩,S1_CR - num_terms將會爲零審查第一列。這是我得到的錯誤 - Msg 102,Level 15,State 1,Line 70 ''@'num_terms'附近語法不正確。 Msg 156,Level 15,State 1,Line 72 關鍵字'else'附近的語法不正確。再次感謝。 – Katheeja

+0

@Katheeja - SO刪除<>當我粘貼抱歉...替換爲「else if」@index = 0和'@term_count <>'@num_terms和'@reviewing <>'@ S1_CR「,您將需要從變量名稱中刪除前導單引號 –

+0

哇!哇..謝謝無限..太好了。上帝祝福你。我會一遍又一遍地學習代碼:-)你可能不瞭解我從我的最後所產生的興奮。再次感謝您的時間。 – Katheeja

0

收到錯誤消息具有遞歸調用做。

在您的解決方案中,您沒有在'END'和程序的測試執行之間放置'GO'。 您有可能將測試的執行編譯爲過程代碼本身。

相關問題