SQL左连接(多重连接条件)

Posted

技术标签:

【中文标题】SQL左连接(多重连接条件)【英文标题】:SQL Left Join (Multiple Join Condition) 【发布时间】:2011-12-11 15:47:05 【问题描述】:

我有两个名为 Check Ins 和 Check Outs 的派生表

签到

CheckDate  CheckIn
---------- ---------
08/02/2011 10:10:03
08/02/2011 15:57:16
07/19/2011 13:58:52
07/19/2011 16:50:55
07/26/2011 15:11:24
06/21/2011 12:36:47
08/16/2011 14:49:36
08/09/2011 13:52:10
08/09/2011 16:54:51
08/23/2011 15:48:58
09/06/2011 15:23:00
09/13/2011 10:09:27
09/13/2011 10:40:14
09/13/2011 11:43:14
09/13/2011 11:59:32
09/13/2011 17:05:24
09/20/2011 11:03:42
09/20/2011 12:08:50
09/20/2011 15:21:06
09/20/2011 15:34:29
09/27/2011 11:34:06
10/04/2011 11:37:59
10/04/2011 15:24:04
10/04/2011 16:57:44
10/11/2011 18:19:33

退房

CheckDate  CheckOut
---------- ---------
08/02/2011 13:29:40
08/02/2011 17:02:25
07/12/2011 17:06:06
07/19/2011 16:40:15
07/19/2011 17:07:35
07/26/2011 14:48:10
07/26/2011 17:27:08
05/31/2011 17:01:39
06/07/2011 17:04:29
06/14/2011 17:08:50
06/21/2011 17:03:46
06/28/2011 17:10:45
07/05/2011 17:02:48
08/16/2011 13:37:36
08/16/2011 17:06:34
08/09/2011 12:00:29
08/09/2011 13:29:36
08/09/2011 14:36:09
08/09/2011 17:00:38
08/23/2011 13:37:11
08/23/2011 17:01:37
09/06/2011 17:00:09
09/13/2011 10:11:50
09/13/2011 11:22:02
09/13/2011 11:47:35
09/13/2011 14:13:36
09/13/2011 14:14:25
09/13/2011 17:08:43
09/20/2011 09:54:55
09/20/2011 11:55:31
09/20/2011 11:55:36
09/20/2011 13:35:16
09/20/2011 15:26:02
09/20/2011 16:33:21
09/20/2011 17:07:52
09/27/2011 11:12:38
10/04/2011 13:26:31
10/04/2011 16:32:56
10/04/2011 17:02:35
10/11/2011 18:25:32

鉴于两个日志都在同一日期并且签出值不能早于签入,我想将签入与签出配对,所以我想出了这个查询

  SELECT A.ChkDt
      AS CheckDate,
         B.CheckIn,
         MIN(A.ChkTm)
      AS CheckOut
    FROM #tempAttLogs
      AS A LEFT JOIN
         (SELECT ChkDt
              AS CheckDate,
                 MIN(ChkTm)
              AS CheckIn
            FROM #tempAttLogs
           WHERE ChkTp = 'I'
        GROUP BY ChkDt) B
      ON A.ChkDt = B.CheckDate
   WHERE ChkTp = 'O' AND
         A.ChkTm > B.CheckIn
GROUP BY A.ChkDt, B.CheckIn

有一个结果集

CheckDate  CheckIn   CheckOut
---------- --------- ---------
06/21/2011 12:36:47  17:03:46
07/19/2011 13:58:52  16:40:15
07/26/2011 15:11:24  17:27:08
08/02/2011 10:10:03  13:29:40
08/09/2011 13:52:10  14:36:09
08/16/2011 14:49:36  17:06:34
08/23/2011 15:48:58  17:01:37
09/06/2011 15:23:00  17:00:09
09/13/2011 10:09:27  10:11:50
09/20/2011 11:03:42  11:55:31
10/04/2011 11:37:59  13:26:31
10/11/2011 18:19:33  18:25:32

问题是我还想包含没有对应对的日志。这怎么可能?

编辑

我的预期结果集必须包含这样的日志

CheckDate  CheckIn   CheckOut
---------- --------- ---------
05/23/2011 NULL      17:04:27

【问题讨论】:

尝试遵循逻辑:我希望能够将in = 2011-02-08T15:57:16out = 2011-02-08T17:02:25 配对,但这不会出现在您的结果集中。应该是?如果您发布了您的 expected 结果集,将会很有帮助。 您是否总是在同一天退房和入住?如果退房时间接近午夜,是否会在第二天办理入住? 使用日期时间而不是单独的日期和时间可能会简化您的查询。 【参考方案1】:

在 WHERE 子句中包含 null 值,例如:

WHERE( ChkTp = 'O' AND
         A.ChkTm > B.CheckIn) OR B.CheckDate IS NULL

【讨论】:

请注意,JOIN ... ON A.ChkDt = B.CheckDate WHERE ... A.ChkTm > B.CheckIn 在 OP 问题中有点相互抵消,所以您可能想要 A.ChkTm >= B.CheckIn 代替【参考方案2】:

您可以将引用右侧表的任何谓词移动到ON 子句而不是WHERE 以避免将JOIN 变成INNER JOIN

例如

ON A.ChkDt = B.CheckDate AND
         A.ChkTm > B.CheckIn
WHERE ChkTp = 'O'

代替

    ON A.ChkDt = B.CheckDate
   WHERE ChkTp = 'O' AND
         A.ChkTm > B.CheckIn

【讨论】:

从未想过会这么简单。谢谢!【参考方案3】:

这可能对解决您的问题很有用(未经测试),尽管它与您的问题略有相关。

select 
  Checkdate, CheckIn as CheckTime, 'I' as CheckAction
from CheckIns 

union all

select 
  Checkdate, CheckOut as CheckTime, 'O' as CheckAction
from CheckOuts
order by 1,2

【讨论】:

以上是关于SQL左连接(多重连接条件)的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server - 选择左连接 NULL 记录 WHERE 条件

sql 各种连接的使用条件,

SQL——左连接(Left join)右连接(Right join)内连接(Inner join)

sql左连接查询+右表带有条件的实现

左连接条件与where条件的区别

使用或条件执行左连接缓慢