2017-06-29 49 views
0

我已經編寫了一個存儲過程,該存儲過程將採用父級部分,通過該部分的物料清單記錄並有條件地連接匹配的子記錄(即包含的部分在這部分的BOM中),但只有滿足特定條件的子記錄(使用我們的命名約定,任何以'。','E'或'ZG'開頭的內容)。在遊標SELECT語句中使用變量

我已經創建了SP,它工作的很好,但只有當我傳入一個[可選]父部件號。我需要爲所有部分運行這個SP,所以我的想法是在遊標內部執行SP,並繼續傳入下一部分,直到沒有剩下的部分處理爲止。我無法解決如何做到這一點,或者甚至可能,因爲在遊標的SELECT語句中(我正在使用存儲過程代碼),我需要傳入一個變量才能使其工作。

這裏是存儲過程的代碼:

CREATE PROCEDURE dbo.usp_BuildBOMLit 
@item_no CHAR(8) = NULL 
AS 
BEGIN 
WITH CTE AS (
     SELECT DISTINCT 
      LTRIM(RTRIM(lvl1.item_no)) as item_no, LTRIM(RTRIM(lvl1.comp_item_no)) as comp_item_no, 
      CASE 
       WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE '.%' 
        THEN 
         LTRIM(RTRIM(lvl1.comp_item_no)) 
       WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'E%' 
        THEN 
         (SELECT TOP 1 LTRIM(RTRIM(comp_item_no)) FROM bmprdstr_sql WHERE LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) AND LTRIM(RTRIM(comp_item_no)) LIKE '.%') 
       WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'ZG%' 
        THEN 
         (SELECT TOP 1 LTRIM(RTRIM(comp_item_no)) FROM bmprdstr_sql WHERE LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) AND LTRIM(RTRIM(comp_item_no)) LIKE '.%') 
        ELSE 
         NULL 
      END as lvl_2_comp_item_no 
     FROM 
      bmprdstr_sql as lvl1 
      LEFT JOIN bmprdstr_sql lvl2 ON lvl1.comp_item_no=lvl2.item_no 
     WHERE 
      (lvl1.item_no = @item_no) 
      AND (lvl1.comp_item_no LIKE '.%' OR lvl1.comp_item_no LIKE 'ZG%' OR lvl1.comp_item_no LIKE 'E%') 
    ) 
    SELECT DISTINCT 
     CASE 
      WHEN LEFT(item_no,1)='.' 
       THEN STUFF(item_no,1,1,'') 
      ELSE 
       item_no 
     END as item_no, 
     part_no = 
      STUFF((SELECT DISTINCT ',' + 
        CASE 
         WHEN LEFT(lvl_2_comp_item_no,1)='.' 
          THEN STUFF(lvl_2_comp_item_no,1,1,'') 
         ELSE lvl_2_comp_item_no 
         END 
        FROM CTE where [email protected]_no FOR XML PATH('')),1,1,'') 
    FROM 
     CTE 
    WHERE 
     lvl_2_comp_item_no IS NOT NULL AND item_no IS NOT NULL 
END 

輸出正是我所需要的格式:

ITEM_NO | part_no

JM9027 | GS10702,LB2391,LB2704,LB2834,LB2896,LB6996

當我創建光標,我使用光標的SELECT聲明相同的代碼,但你可以看到,如果需要父(@itemno)在傳遞。我已經試過了,無濟於事:

SET NOCOUNT ON; 
DECLARE @itemno CHAR(15); 
DECLARE @partno VARCHAR(254); 
DECLARE @outside_cursor AS CURSOR; 

SET @outside_cursor = CURSOR FAST_FORWARD FOR 
WITH CTE AS 
(SELECT DISTINCT 
     LTRIM(RTRIM(lvl1.item_no)) AS item_no, 
     LTRIM(RTRIM(lvl1.comp_item_no)) AS comp_item_no, 
     CASE 
      WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE '.%' 
       THEN LTRIM(RTRIM(lvl1.comp_item_no)) 
      WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'E%' 
       THEN 
        (SELECT TOP 1 
         LTRIM(RTRIM(comp_item_no)) 
        FROM 
         bmprdstr_sql 
        WHERE 

LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) 
         AND LTRIM(RTRIM(comp_item_no)) LIKE '.%' 
        ) 
      WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'ZG%' 
       THEN 
        (SELECT TOP 1 
         LTRIM(RTRIM(comp_item_no)) 
        FROM 
         bmprdstr_sql 
        WHERE 

LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) 
         AND LTRIM(RTRIM(comp_item_no)) LIKE '.%' 
        ) 
      ELSE NULL 
     END AS lvl_2_comp_item_no 
FROM 
    bmprdstr_sql AS lvl1 
    LEFT JOIN bmprdstr_sql lvl2 ON lvl1.comp_item_no=lvl2.item_no 
WHERE 
    (lvl1.item_no = @itemno) -- <-- problem 
    AND (lvl1.comp_item_no LIKE '.%' OR lvl1.comp_item_no LIKE 'ZG%' 
OR lvl1.comp_item_no LIKE 'E%') 
) 
SELECT DISTINCT 
    CASE 
     WHEN LEFT(item_no,1)='.' 
      THEN STUFF(item_no,1,1,'') 
     ELSE item_no 
    END AS item_no, 
    part_no = 
     STUFF(
      (SELECT DISTINCT ',' + 
       CASE 
        WHEN LEFT(lvl_2_comp_item_no,1)='.' 
         THEN STUFF(lvl_2_comp_item_no,1,1,'') 
        ELSE lvl_2_comp_item_no 
       END 
      FROM 
       CTE 
      WHERE 
       [email protected] FOR XML PATH('')),1,1,'') 
        --^problem 
FROM 
    CTE 
WHERE 
    lvl_2_comp_item_no IS NOT NULL 
    AND item_no IS NOT NULL 

OPEN @outside_cursor; 
FETCH NEXT FROM @outside_cursor INTO @itemno, @partno; 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     INSERT INTO items_parts (item_no, part_no) 
     VALUES (@itemno, @partno) 
    FETCH NEXT FROM @outside_cursor INTO @itemno, @partno 
    END 
CLOSE @outside_cursor 
DEALLOCATE @outside_cursor 

有關如何完成此任務的任何建議?

+1

不確定你爲什麼使用遊標來插入數據。我沒有試圖解析這個大的查詢來真正看到它在做什麼,但是這可以被重寫爲一個基於集合的插入。這裏是一個開始的好地方。 http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ –

+0

@SeanLange每個關於SQL遊標的問題都以一種形式結束或其他。我在去光標前嘗試使用基於集合的方法。 – SpaceAge

+0

這是因爲幾乎每個遊標都可以用基於集合的方法而不是RBAR來解決。 –

回答

0

無論您是否需要光標,並將您的問題視爲學術問題,都會以錯誤的方式使用光標。

你有一個proc,做你想做的,但只有一個父母。合併遊標的方法是使用遊標遍歷父級,並且每次循環時只用一個新的item_no填充item_no變量,然後在遊標內運行現有代碼。

您不需要在兩個單獨的查詢中執行SELECT和INSERT,您可以在光標中執行一個INSERT..SELECT。遊標只是迭代你的item_no值列表。

+0

當你說我不需要在單獨的查詢中執行SELECT和INSERT時,你是說我可以在遊標定義中執行INSERT ... SELECT嗎?像'SET @outside_cursor = CURSOR FAST FORWARD FOR INSERT INTO items_parts VALUES @itemno,@partno WITH CTE AS(SELECT ....)',然後在WHILE循環中調用'FETCH NEXT'? – SpaceAge

+0

不,遊標定義只是您想用作'@ itemno'變量的'item_no'的SELECT。 INSERT..SELECT是放在遊標循環中的操作,因此它是針對每個'item_no'執行的。 –

+0

感謝您的幫助@Tab Alleman。我能夠在不使用遊標的情況下完成此任務。 – SpaceAge

0

我明白了;

我覺得你有什麼是CTE返回數據的單行(或者(N)的數據行,但只有唯一的@itemno)

CTE(item_no, comp_item_no, lvl_2_comp_item_no) 
     AS (
      --.... and the row will correspond to the @itemno provided 

但你要代替的是CTE它返回值對於所有可能的[ietm_no](東西這將導致在幕後臨時表3列[ITEM_NO]設置,[comp_item_no],[lvl_2_comp_item_no]與(n)的行。

然後你可以使用你的CURSOR逐個循環,將它們加載到CURSOR VARIABLES中,例如:

FETCH NEXT FROM @outside_cursor INTO @itemno, @partno... 

並使用唯一的@itemno處理每行的插入。

順便說一句,我注意到,你命名你的光標爲@outside_cursor這意味着可能有一個@inside_cursor以及地方?如果你嵌套遊標(這不是最好的選擇),請注意@@ FETCH_STATUS是一個全局變量,你需要爲每個遊標單獨管理這個變量的值。

我看到這個對嗎?

+0

CTE的結果是父項item_no在item_no列中重複,comp_item_no是父項下的第一個子級,並且如果comp_item_no值以'。','E'或'ZG'開始,它將執行子查詢並找到符合相同條件的所有子項。 以下查詢將刪除'。'從item_no的前面(如果有的話),並將所有lvl_2_comp_item_no連接成逗號分隔列表。 此外,遊標被命名爲'@ outside_cursor',因爲我一直試圖通過創建一個嵌套遊標來解決這個問題,並且從來沒有重新命名它。 – SpaceAge

+0

好的,這很好,光標不嵌套,以及我的建議如何?看來你沒有正確使用光標。我認爲你需要加載所有itemno的數據集,然後逐個處理它...有道理? – Milan

+0

你所描述的最終是我想要的結果,但我無法弄清楚正確的語法用於返回數據而不使用CTE中的變量。我將嘗試您的建議並執行SP打開以在定義和運行遊標以遍歷行之前將所有數據插入臨時表。我會回報 - 謝謝你的建議。 – SpaceAge

0

我很感謝這個問題的幫助。我回到繪圖板,並能夠完成我需要的存儲過程和自加入查詢 - 無需光標。

相關問題