2017-06-29 4 views
0

親パートを取るストアドプロシージャを記述し、そのパートのBOM(bill-of-materials)レコードを調べ、条件を満たす子レコード(つまり、含まれるパーツ特定の基準(私たちの命名規則、 '。'、 '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カーソルに関するすべての質問は、このコメントとともに1つの形式で終わりますまたは別のもの。私はカーソルに行く前にセットベースのアプローチを使ってみました。 – SpaceAge

+0

これは、ほとんどすべてのカーソルがRBARの代わりにセットベースのアプローチで解決できるためです。 –

答えて

0

あなたがカーソルを必要としていなくても、あなたの質問を学術的なものとして扱うかどうかは、間違った方法でカーソルを使用しています。

あなたは1つの親に対してのみ、あなたが望むことをするprocを持っています。カーソルを組み込む方法は、カーソルを使用して親を反復し、ループするたびにitem_no変数に新しいitem_no変数を設定し、カーソル内に既存のコードを実行することです。

SELECTとINSERTを別々の2つのクエリで実行する必要はありません。カーソル内で1つの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

あなたのお手伝いをよろしくお願いいたします。私はカーソルを使わずにこれを達成できました。 – SpaceAge

0

は、私が何を持っていること(あるいは(n)の@itemnoにのみ固有のデータの行はなく)

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

はなく、何を代わりにしたいことはCTEであるデータの単一の行を返すCTEだと思いますこれは(N)の行と[lvl_2_comp_item_no]、[comp_item_no]、値が3列[item_no]と背後一時テーブルをもたらすべきであるすべての可能な[ietm_no](何かをを設定返す。そして

あなたはCURSORを使ってこれらを1つずつループし、CURSOR VARIABLESにロードします。

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

各行の挿入を一意の@itemnoで処理します。

ところで、カーソルを@outside_cursorと指定したことに気付きました。これは、@ in-ide_cursorもどこかにある可能性があることを意味していますか?カーソルをネストしている場合(これは最善の選択ではありません)、@@ FETCH_STATUSはグローバル変数であり、この変数の値をカーソルごとに個別に管理する必要があります。

私はこの権利を見ていますか?

+0

CTEの結果は、item_no列の親item_noの繰り返しであり、comp_item_noは親の下の最初の子レベルであり、comp_item_noの値が '。'、 'E'または 'ZG'で始まる場合、サブクエリを検索し、同じ条件に一致するTHAT項目の子を検索します。 次に、次のクエリで '。'が削除されます。 item_noが存在する場合は、item_noの前から入力し、すべてのlvl_2_comp_item_noをコンマで区切ったリストに連結します。 また、カーソルはネストされたカーソルを作成することでこれを解決しようとしていて、名前を変更していないため、 '@ outside_cursor'という名前になっています。 – SpaceAge

+0

OK、カーソルがネストされていないこと、そして上記の私の提案はどうですか?カーソルを正しい方法で使用していないようです。私はすべてのitemnoのデータセットをロードし、それを一つずつ処理する必要があると思います...意味がありますか? – Milan

+0

あなたが描写したものは最終的に私が望むものですが、CTEの変数を使用せずにデータを返すための正しい構文を理解することはできません。カーソルを定義して実行して行を反復処理する前に、すべてのデータを一時テーブルに挿入するようにSPを開いて実行することをお勧めします。私は戻って報告します - 提案していただきありがとうございます。 – SpaceAge

0

この問題のサポートに感謝します。私はドローイングボードに戻って、ストアドプロシージャと自己結合クエリで必要なものを達成することができました。カーソルは必要ありません。

関連する問題