Return 结果基于两个基于 Id 的结果集,不考虑行数

Return result based on two results set based on Id, irrespective of rows count

我从两个不同的来源 @Table1, @Table2 接收数据集,table 都有 Id 列。对于相同的 ID,两个来源 return 不同数量的记录。

我想合并基于 @MainTable 的结果,它具有来自 @Table1@Table2 的所有可能 ID。如果另一个 table 没有相同数量的记录,那么它可以与 NULL.

一起应用

示例数据和table设计:

DECLARE @MainTable TABLE (Id INT, [Name] VARCHAR (50));
INSERT INTO @MainTable (Id, [Name]) VALUES (1, 'One'), (2, 'Two'), (3, 'Three');

DECLARE @Table1 TABLE (Id INT, Val1 INT, Val2 INT);
INSERT INTO @Table1 (Id, Val1, Val2) VALUES 
(1, 11, 12), (1, 22, 23), (1, 33, 34), (1, 38, 39), 
(2, 31, 32), (2, 34, 35), 
(3, 44, 45);

DECLARE @Table2 TABLE (Id INT, Val3 INT, Val4 INT);
INSERT INTO @Table2 (Id, Val3, Val4) VALUES 
(1, 20, 21), (1, 25, 26), 
(2, 30, 31), (2, 33, 34), (2, 36, 37), (2, 38, 39), (2, 40, 41),
(3, 51, 52), (3, 54, 55), (3, 56, 57), (3, 58, 59);

预期输出:

Id Name Val1 Val2 Val3 Val4
1 One 11 12 20 21
1 One 22 23 25 26
1 One 33 34 NULL NULL
1 One 38 39 NULL NULL
2 Two 31 32 30 31
2 Two 34 35 33 34
2 Two NULL NULL 36 37
2 Two NULL NULL 38 39
2 Two NULL NULL 40 41
3 Three 44 55 51 52
3 Three NULL NULL 54 55
3 Three NULL NULL 56 57
3 Three NULL NULL 58 59

我正在使用 SQL Server 2012。我已经尝试了下面的一些代码,但没有帮助:

SELECT MT.Id, MT.[Name], A.Val1, A.Val2, B.Val3, B.Val4
FROM @MainTable MT
OUTER APPLY ( SELECT * FROM @Table1 T1 WHERE T1.Id = MT.Id ) A
OUTER APPLY ( SELECT * FROM @Table2 T2 WHERE T2.Id = MT.Id ) B

SELECT *
FROM @MainTable MT
LEFT OUTER JOIN @Table1 T1 ON T1.Id = MT.Id
LEFT OUTER JOIN @Table2 T2 ON T2.Id = MT.Id

在行之间读取,但如果您不关心哪些行连接到哪些行(因为我看不到 @Table1@Table2 中的行之间没有关系),您可以这样做:

WITH T1 AS(
    SELECT T1.Id,
           T1.Val1,
           T1.Val2,
           ROW_NUMBER() OVER (PARTITION BY T1.Id ORDER BY (SELECT NULL)) AS RN --Define your ORDER BY properly here
    FROM @Table1 T1),
T2 AS(
    SELECT T2.Id,
           T2.Val3,
           T2.Val4,
           ROW_NUMBER() OVER (PARTITION BY T2.Id ORDER BY (SELECT NULL)) AS RN --Define your ORDER BY properly here
    FROM @Table2 T2),
RNs AS(
    SELECT T1.Id,
           T1.RN
    FROM T1
    UNION
    SELECT T2.Id,
           T2.RN
    FROM T2)
SELECT MT.Id,
       T1.Val1,
       T1.Val2,
       T2.Val3,
       T2.Val4
FROM @MainTable MT
     JOIN RNs ON MT.Id = RNs.Id
     LEFT JOIN T1 ON RNs.Id = T1.ID
                 AND RNs.RN = T1.RN
     LEFT JOIN T2 ON RNs.Id = T2.ID
                 AND RNs.RN = T2.RN;

db<>fiddle

Larnu 先于我。但我仍在发布我的答案,因为我认为如果数据集变大,我的答案会更快一些。

DECLARE @MainTable TABLE (Id INT, [Name] VARCHAR (50));
INSERT INTO @MainTable (Id, [Name]) VALUES (1, 'One'), (2, 'Two'), (3, 'Three');

DECLARE @Table1 TABLE (Id INT, Val1 INT, Val2 INT);
INSERT INTO @Table1 (Id, Val1, Val2) VALUES 
(1, 11, 12), (1, 22, 23), (1, 33, 34), (1, 38, 39), 
(2, 31, 32), (2, 34, 35), 
(3, 44, 45);

DECLARE @Table2 TABLE (Id INT, Val3 INT, Val4 INT);
INSERT INTO @Table2 (Id, Val3, Val4) VALUES 
(1, 20, 21), (1, 25, 26), 
(2, 30, 31), (2, 33, 34), (2, 36, 37), (2, 38, 39), (2, 40, 41),
(3, 51, 52), (3, 54, 55), (3, 56, 57), (3, 58, 59);


with cte1 as (
    select
        t1.*,
        row_number() over (partition by t1.Id order by t1.Val1) as seqno 
    from @Table1 t1
),
cte2 as (
    select
        t2.*,
        row_number() over (partition by t2.Id order by t2.Val3) as seqno 
    from @Table2 t2
),
cte3 as (
    select isnull(c1.Id, c2.Id) as Id, c1.Val1, c1.Val2, c2.Val3, c2.Val4
    from cte1 c1
        full outer join cte2 c2 on (c2.Id = c1.Id and c2.seqno = c1.seqno)
)
select
    m.Id,
    m.[Name],
    c3.Val1,
    c3.Val2,
    c3.Val3,
    c3.Val4
from @MainTable m
    left outer join cte3 c3 on (c3.Id = m.Id);