2016-12-21 4 views
2

このプロジェクトのデータには、セミコロンで区切られた2つの列が含まれています。これらは実際に順序付けられたペアです。たとえば、「a; b; c」、「x; y; z」、「a」は「x」と対になっています。クエリの目標は、この関係が一度に1行ずつ明確に表される表を作成することです。ここでSQL Server CTEが正しく結合されない

は再作成するサンプル・データへのスクリプトです:

DROP TABLE IF EXISTS dbo.sampleData; 
DROP TABLE IF EXISTS dbo.lookupCPT; 
GO 

CREATE TABLE sampleData 
(
    numRow bigint IDENTITY(1,1) NOT NULL CONSTRAINT PK_numRow PRIMARY KEY, 
    sDelimQty varchar(MAX) NULL, 
    sDelimCPT varchar(MAX) NULL 
) 

CREATE TABLE lookupCPT 
(
    numRow bigint IDENTITY(1,1) NOT NULL CONSTRAINT PK_numRowCPT PRIMARY KEY, 
    sCPTCode varchar(10) NULL, 
    decCPTRate decimal(16,2) NULL 
) 

INSERT [dbo].[lookupCPT] ([numRow], [sCPTCode], [decCPTRate]) 
VALUES (1, N'123', CAST(4.00 AS Decimal(16, 2))) 

INSERT [dbo].[lookupCPT] ([numRow], [sCPTCode], [decCPTRate]) 
VALUES (2, N'456', CAST(5.00 AS Decimal(16, 2))) 

INSERT [dbo].[lookupCPT] ([numRow], [sCPTCode], [decCPTRate]) 
VALUES (3, N'789', CAST(7.00 AS Decimal(16, 2))) 

INSERT [dbo].[sampleData] ([numRow], [sDelimQty], [sDelimCPT]) 
VALUES (1, N'1;2', N'123;789') 

INSERT [dbo].[sampleData] ([numRow], [sDelimQty], [sDelimCPT]) 
VALUES (2, N'3', N'456') 

私たちは、共通テーブル式を使用してこれを実現しようとした:

WITH Qty_CTE (numRowQ, Qty) AS 
(
    SELECT numRow, value 
    FROM sampleData 
    CROSS APPLY STRING_SPLIT(sDelimQty, ';') 
), 
CPT_CTE (numRowC, CPT) AS 
(
    SELECT numRow, value 
    FROM sampleData 
    CROSS APPLY STRING_SPLIT(sDelimCPT, ';') 
) 
SELECT * 
FROM sampleData 
JOIN CPT_CTE c on c.numRowC = sampleData.numRow 
JOIN Qty_CTE q on q.numRowQ = sampleData.numRow 

ただし、これを行うことで、行の量を倍増します私たちの出力:

q1

しかし、私

q2

任意のアイデア:F我々は、いずれか二つのうちの一つは、それが正しく返すジョイン削除しますか?ありがとうございました

すべての有用な回答の後、以下は最終的な解決策です。乾杯!

WITH Qty_CTE (numRowQ, Qty, RN) AS 
(
    SELECT 
     numRow, value, 
     ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN 
    FROM 
     sampleData 
    CROSS APPLY 
     STRING_SPLIT(sDelimQty, ';') 
), 
CPT_CTE (numRowC, CPT, CPTRate, RN) AS 
(
    SELECT 
     s.numRow, value as CPT, l.decCPTRate as CPTRate, 
     ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN 
    FROM 
     sampleData s 
    CROSS APPLY 
     STRING_SPLIT(sDelimCPT, ';') 
    JOIN 
     lookupCPT l ON value = l.sCPTCode 
) 
SELECT 
    numRow, sDelimCPT, sDelimQty, CPT, CPTRate, Qty, CPTRate * Qty as Total 
FROM 
    sampleData 
JOIN 
    CPT_CTE c on c.numRowC = sampleData.numRow 
JOIN 
    Qty_CTE q on q.numRowQ = sampleData.numRow AND c.RN = q.RN 
+0

は、常に区切られた数字です*昇順で? –

+0

残念ながら保証はありません: - 私のために\ –

+0

、q1はq2と同様に論理的です。 – Sebas

答えて

0

STRING_SPLIT機能が順序を保持している場合、これは機能します。

WITH Qty_CTE (numRowQ, Qty, RN) AS 
(
SELECT numRow, value, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN 
FROM sampleData 
    CROSS APPLY STRING_SPLIT(sDelimQty, ';') 
), 
CPT_CTE (numRowC, CPT, RN) AS 
(
SELECT numRow, value, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN 
FROM sampleData 
    CROSS APPLY STRING_SPLIT(sDelimCPT, ';') 
) 
SELECT * FROM sampleData 
JOIN CPT_CTE c on c.numRowC = sampleData.numRow 
JOIN Qty_CTE q on q.numRowQ = sampleData.numRow AND c.RN = q.RN 
+0

残念ながら、実際にはSTRING_SPLIT機能はSQL Server 2016リリースの一部です。また、私はこれを試して、ORDER BY SELECT NULLは解釈できません。 –

+0

これでうまくいくはずです(SELECT NULLのまわりの括弧は忘れてしまいました)。 STRING_SPLITについては、自分で作成するか、STRING_SPLITのマニュアルを参照して保証されているかどうかを確認してください。 – DVT

+0

Genius!これは正解です。どうもありがとうございます!!! –

0

例q1とq2は、どちらも期待どおりに動作します。 Qty_CTEの基数は3です(レコード1が2回、レコード2が1回表示されます)。CPT_CTEも同じです。 sampleDataは2の基数を(各行が一度のみ表示されます)

あなたはPKに参加しているので、れるsampleDataは、X持つQty_CTE X CPT_CTEそれはNUMROW 1と1x1x1のレコードのために(1x2x2レコードをした、5つのレコードを返す必要がありますnumrow 2)。 Qty_CTEまたはCPT_CTEのいずれかを削除すると、3レコード(numrow 2の場合は1x1x1レコード、numrow 1の場合は1x2レコード)が返されます。

期待した結果があれば、その結果に基づいて解決策を提案することができます。

+0

私はあなたが正しいと信じていますが、なぜこれが起こりますか? sampleData x Qty_CTE x CPT_CTE? –

+0

シンプルセット理論。簡単に言えば、各テーブルはWHEREフィルタに従って計算され、順番に1つの* resultset *になります。次に、これらの結果セットが相互に結合されます。 INNER JOINの場合は、* intersection *となりますので、上記のようになります。 – Sebas

+0

セットAとセットBとの交差は、条件なしでA×Bレコードセットになります。私はこれを説明するビット不器用だけど、私はそれをしなければならなかったことはありません実現:)私は – Sebas

関連する問題