繁体   English   中英

SQL Server CTE不能正确加入

[英]SQL Server CTE doesn't Join Properly

该项目的数据包含两列,以分号分隔的字符串。 这些实际上是有序对。 因此,例如,在:“ a; b; c”,“ x; y; z”中,“ a”与“ x”配对。 我们的查询目标是创建一个表,在该表中一次清楚地表示这一关系。

这是一个重新创建示例数据的脚本:

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

有任何想法吗? 非常感谢

在提供所有有用的答案之后,下面是最终的解决方案。 干杯!

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

如果您的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

您的示例q1和q2均按预期工作。 Qty_CTE的基数为3(记录1出现两次,记录2出现一次), CPT_CTE也是CPT_CTE sampleData的基数为2(每行仅出现一次)

由于您正在加入PK, Qty_CTE CPT_CTE x Qty_CTE x CPT_CTE应该返回5条记录(记录数为1的记录为1x2x2,记录数为2的记录为1x1x1)。 如果删除Qty_CTECPT_CTE它应该返回3条记录(确实如此)(第2行为1x1x1记录,第1行为1x2记录)。

如果您有一个预期的结果,我们可以提出一个解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM