【问题标题】:SQL Full Outer JoinSQL 完全外连接
【发布时间】:2012-01-06 17:18:14
【问题描述】:

我有一个名为“日志”的表,其中包含以下值:

CheckDate        CheckType        CheckTime
-------------------------------------------
2011-11-25       IN               14:40:00
2011-11-25       OUT              14:45:00
2011-11-25       IN               14:50:00
2011-11-25       OUT              14:55:00
2011-11-25       IN               15:00:00
2011-11-25       OUT              15:05:00
2011-11-25       IN               15:15:00
2011-11-25       OUT              15:20:00
2011-11-25       IN               15:25:00
2011-11-25       OUT              15:30:00
2011-11-25       OUT              15:40:00
2011-11-25       IN               15:45:00

我想使用前面的表格来产生以下结果:

CheckDate        CheckIn        CheckOut
-----------------------------------------
2011-11-25       14:40:00       14:45:00
2011-11-25       14:50:00       14:55:00
2011-11-25       15:00:00       15:05:00
2011-11-25       15:15:00       15:20:00
2011-11-25       15:25:00       15:30:00
2011-11-25       NULL           15:40:00
2011-11-25       15:45:00       NULL

到目前为止,我已经想出了这个结果集:

CheckDate        CheckIn        CheckOut
-----------------------------------------
2011-11-25       14:40:00       14:45:00
2011-11-25       14:50:00       14:55:00
2011-11-25       15:00:00       15:05:00
2011-11-25       15:15:00       15:20:00
2011-11-25       15:25:00       15:30:00
2011-11-25       15:45:00       NULL

问题是我无法在没有 CheckIns 的情况下生成日志:

CheckDate        CheckIn        CheckOut
-----------------------------------------
2011-11-25       NULL           15:40:00

CheckIn - CheckOut 配对顺序和顺序是时间值递增的。

编辑:这是我当前的查询

SELECT Ins.CheckDate,
       Ins.CheckTime,
       Outs.CheckTime

  FROM (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'I') Ins 

  FULL OUTER JOIN

       (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'O') Outs

    ON Ins.CheckDate = Outs.CheckDate AND
       Ins.CheckTime < Outs.CheckTime

【问题讨论】:

  • “到目前为止我已经想出了这个结果集”:你能分享一下 SQL 吗?
  • 你能发布你有给你结果的查询吗?
  • 是日志表的完整范围还是每个条目都有其他键?能否包含用于生成当前结果集的 SQL?
  • 我修复了更新引入的回归问题。它现在应该涵盖所有可能的情况。

标签: sql sql-server-2005 tsql outer-join


【解决方案1】:

部分优化器不支持 sql 的“FULL OUTER JOIN” 所以, 查询应该是:

SELECT Ins.CheckDate,
       Ins.CheckTime,
       Outs.CheckTime

  FROM (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'I') Ins 

  LEFT OUTER JOIN

       (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'O') Outs

    ON Ins.CheckDate = Outs.CheckDate AND
       Ins.CheckTime < Outs.CheckTime

UNION

SELECT Ins.CheckDate,
       Ins.CheckTime,
       Outs.CheckTime

  FROM (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'I') Ins 

  RIGHT OUTER JOIN

       (SELECT CheckDate,
               CheckTime
          FROM Logs
         WHERE CheckType = 'O') Outs

    ON Ins.CheckDate = Outs.CheckDate AND
       Ins.CheckTime < Outs.CheckTime

【讨论】:

    【解决方案2】:

    这应该可行:

    ;WITH x AS (
       SELECT CheckDate, CheckType, CheckTime
             ,row_number() OVER (ORDER BY CheckDate, CheckTime) As rn
       FROM #t
    )
    SELECT CASE WHEN x.CheckType = 'IN' OR x.rn = 1 THEN x.CheckDate 
                                                   ELSE y.CheckDate END AS CheckDate
          ,CASE WHEN x.CheckType = 'IN'  THEN x.CheckTime ELSE NULL END AS CheckIn
          ,CASE WHEN y.CheckType = 'OUT' THEN y.CheckTime
                WHEN x.CheckType = 'OUT' THEN x.CheckTime ELSE NULL END AS CheckOut
    FROM   x
    LEFT   JOIN x AS y ON y.rn = x.rn + 1
    WHERE  x.CheckType = 'IN'
    OR     y.CheckType = 'OUT'
    OR     x.rn = 1
    

    它准确地产生请求的输出并涵盖特殊情况

    • OUT 后面跟着另一个 OUT(缺少 IN
    • IN 后面跟着另一个 IN(缺少 OUT
    • IN 后面没有任何内容(最后一行)。
    • 第一行以OUT 开头。

    试试working demo on data.SE

    【讨论】:

    • 不错的解决方案。简单高效。
    • @JustinGrant:谢谢,但实际上如果第一行以“OUT”开头,则它会丢失。不是问题,而是科学!现在也涵盖了这一点。在 CheckOut 的 CASE 语句中从 y.CheckType 切换到 x.CheckType 是一种特殊处理,在这种情况下保持简单且高效。 :)
    • 常用表表达式,这个我不熟悉。我总是依赖派生表或临时表,我认为这些表执行时间更长。 (我说得对吗?)现在我打算用这种方法重新提出我的查询。非常感谢你欧文。 :)
    • @TormentMarch:CTE 的主要优点:您可以在相同或不同的查询级别上多次重用 CTE,并且代码更具可读性。性能在其他方面类似于子查询。还有递归 CTE,但那是另一回事了……
    猜你喜欢
    • 1970-01-01
    • 2017-07-05
    • 2018-07-12
    • 2015-12-11
    • 1970-01-01
    • 2013-03-11
    • 2015-07-17
    • 1970-01-01
    相关资源
    最近更新 更多