在具有特定条件的子查询上左连接

Posted

技术标签:

【中文标题】在具有特定条件的子查询上左连接【英文标题】:LEFT Join on a Subquery with specific criteria 【发布时间】:2021-11-11 15:07:24 【问题描述】:

我有两个要加入的表

table1
----------------------------
Id         Name         Num
123X       Apple        17

table2
-------------------------------------------------
id           EndDt         SomeVal      
123X         10/1/2021     xxx
123X         3/1/2022      yyy

我正在尝试从 table1 aLEFT JOIN table2 b on a.id = b.id 中进行选择 - 但是,我只想在 table2 中的 ID 上选择 MAX(EndDt)

Select a.*, b.SomeVal
from table1 a 
    LEFT OUTER JOIN table2 b on a.id=b.id // and b.MAX(EndDt)

这样的事情可行吗?

【问题讨论】:

再添加几行样本数据,同时指定预期结果。 【参考方案1】:

有几种方法可以做到这一点。不过,我对您的数据做了一些假设。

    LEFT JOIN 与子查询一起使用:
    SELECT T1.*,
           sq.SomeVal
    FROM dbo.Table1 T1
         LEFT JOIN (SELECT ROW_NUMBER() OVER (PARTITION BY t2.Id ORDER BY t2.EndDt DESC) AS RN,
                           t2.Id,
                           t2.SomeVal
                    FROM dbo.Table2 T2) sq ON T1.Id = T2.Id
                                          AND T2.RN = 1;
    
    使用APPLYTOP
    SELECT T1.*,
           sq.SomeVal
    FROM dbo.Table1 T1
         OUTER APPLY (SELECT TOP (1)
                             t2.Id,
                             t2.SomeVal
                      FROM dbo.Table2 T2
                      WHERE T2.Id = T1.Id
                      ORDER BY T2.EndDt DESC) sq;
    
    使用 CTE 并获取每组的“前 1”行:
    WITH CTE AS(
        SELECT T1.*,
               T2.SomeVal,
               ROW_NUMBER() OVER (PARTITION BY T1.ID ORDER BY T2.MaxDt DESC) AS RN
        FROM dbo.Table1 T1
             LEFT JOIN dbo.Table2 T2 ON T1.Id = T2.Id)
    SELECT *
    FROM CT
    WHERE RN = 1;
    
    使用TOP (1) WITH TIES:
    SELECT TOP (1) WITH TIES
           T1.*,
           T2.SomeVal
    FROM dbo.Table1 T1
         LEFT JOIN dbo.Table2 T2 ON T1.Id = T2.Id
    ORDER BY ROW_NUMBER() OVER (PARTITION BY T1.ID ORDER BY T2.MaxDt DESC) ASC;
    

请注意,如果 ID 在表 Table1 中不是唯一的(因此我对您的数据做出假设),选项 3 和 4 将无法按预期工作。

【讨论】:

【参考方案2】:

我建议先使用窗口化的 ROW_NUMBER 函数获取最大值 table2,然后加入该子查询。

;WITH cte AS (
    SELECT *, [Row] = ROW_NUMBER() OVER (PARTITION BY b.Id ORDER BY b.EndDt DESC)
    FROM table2 b
)
SELECT a.*, cte.SomeVal
FROM table1 a
LEFT JOIN cte ON a.id = cte.id AND cte.[Row] = 1

【讨论】:

【参考方案3】:

对于单个值,使用相关子查询:

SELECT
    a.id,
    a.name,
    a.num,
    (
        SELECT TOP 1 SomeValue 
        FROM table2 As b 
        WHERE b.id = a.id 
        ORDER BY b.EndDt DESC
    ) As SomeVal
FROM
    table1 a

【讨论】:

以上是关于在具有特定条件的子查询上左连接的主要内容,如果未能解决你的问题,请参考以下文章

在连接的子查询中重复 WHERE 标准

Postgresql:FROM 中的子查询必须有别名 - 具有多个连接

SELECT中(非常)常用的子查询操作

MySQL学习10 - 多表查询

mysql常用基础操作语法~~子查询命令行模式

MySQL多表查询