存在查询未产生预期结果时的 T-SQL 案例

Posted

技术标签:

【中文标题】存在查询未产生预期结果时的 T-SQL 案例【英文标题】:T-SQL Case When Exists Query Not Producing Expected Results 【发布时间】:2018-09-06 10:59:48 【问题描述】:

我已经整理了一个查询,它应该显示在选定日期之前和之后有事件的每条记录。添加了一个额外的列,如果记录在日期之前有事件,则设置为 True/False,如果记录在第二个日期之后有事件,则设置为 True/False。

问题是我知道事件表中有记录在第一个日期之前而不是在第二个日期之后有事件,但它们没有出现在我的查询中。只有对两者都为 True 的结果才会从查询中出来。不知道我做错了什么。

SELECT DISTINCT DeviceName,dPhone,DSIMID,  Vehicles.reg, DeviceID,
CASE
WHEN EXISTS (SELECT eventID FROM [events] WHERE [events].sysdatetime < 
'2018-09-05 11:46:00.000')
THEN 'True' ELSE 'False' 
END AS [WasReportingBeforeDate],
CASE
WHEN EXISTS (SELECT eventID FROM [events] WHERE [events].sysdatetime > 
'2018-09-05 11:46:00.000')
THEN 'True' ELSE 'False' END AS [WasReportingAfterDate]
FROM [Devices]
INNER JOIN Vehicles ON Vehicles.DevID = Devices.DevID
INNER JOIN [events] ON Devices.DevID = [events].DeviceID;

当前输出示例为:

Z3243   1  1 AA05 AAA 1 True    True

预期输出:

Z3243   1  1 AA05 AAA 1 True    False

此记录没有比第二个日期更新的数据,因此它应该返回 false

【问题讨论】:

左对齐 SQL 太难读了... 样本数据和期望的结果真的很有帮助。 那些子查询没有链接到外部查询。所以DeviceID 过滤器不适用于它们。 DISTINCT 是说 event 不应该以这种方式加入。 【参考方案1】:

您没有关联您的EXISTS,因此如果表中存在任何记录与[events].sysdatetime &gt; '2018-09-05 11:46:00.000',那么您的EXISTS 将始终返回true。

你想要这样的东西:

...
CASE WHEN EXISTS (SELECT *
                  FROM [events] e2
                  WHERE e2.sysdatetime > '2018-09-05 11:46:00.000'
                  AND e2.eventID = e.eventID) --here
...
FROM [Devices] d
INNER JOIN Vehicles v ON b.DevID = d.DevID
INNER JOIN [events] e ON d.DevID = e.DeviceID;

【讨论】:

【参考方案2】:

我会将查询拆分为 2 个单独的查询,然后使用 union all 将结果集重新组合在一起。如果您需要一个标志来确定事件,然后才能将其硬编码到以下查询中。

   ;WITH EventsBefore AS 
    (
    SELECT DISTINCT
           DeviceName,
           dPhone,
           DSIMID,
           Vehicles.reg,
           DeviceID,
    FROM [Devices]
         INNER JOIN Vehicles ON Vehicles.DevID = Devices.DevID
         INNER JOIN [events] ON Devices.DevID = [events].DeviceID
         INNER JOIN lastEvent ON Devices.DevID = lastEvent.devID;
    WHERE [events].sysdatetime < '2018-09-05 11:46:00.000'

    )

     ,EventsAfter AS 
    (
    SELECT DISTINCT
           DeviceName,
           dPhone,
           DSIMID,
           Vehicles.reg,
           DeviceID,
    FROM [Devices]
         INNER JOIN Vehicles ON Vehicles.DevID = Devices.DevID
         INNER JOIN [events] ON Devices.DevID = [events].DeviceID
         INNER JOIN lastEvent ON Devices.DevID = lastEvent.devID;
    WHERE WHERE [events].sysdatetime > '2018-09-05 11:46:00.000'

    )

    SELECT * FROM EventsBefore
    UNION ALL 
    SELECT * FROM EventsAfter

【讨论】:

【参考方案3】:
    摆脱加入events 并随意删除多余的DISTINCT 将连接谓词放入现在缺少的子查询中

像这样:

SELECT DeviceName,dPhone,DSIMID,  Vehicles.reg, DeviceID,
CASE
  WHEN EXISTS (SELECT 1 FROM [events] e 
    WHERE e.sysdatetime < '2018-09-05 11:46:00.000'
    AND e.DeviceID = Devices.DevID)
  THEN 'True' ELSE 'False' 
END AS [WasReportingBeforeDate],
CASE
  WHEN EXISTS (SELECT 1 FROM [events] e 
    WHERE e.sysdatetime > '2018-09-05 11:46:00.000'
    AND e.DeviceID = Devices.DevID)
THEN 'True' ELSE 'False' END AS [WasReportingAfterDate]
FROM [Devices]
INNER JOIN Vehicles ON Vehicles.DevID = Devices.DevID

【讨论】:

以上是关于存在查询未产生预期结果时的 T-SQL 案例的主要内容,如果未能解决你的问题,请参考以下文章

列表中的元素计数未产生预期结果

数据库日期/时间比较未产生预期结果?

带有子行的 T-SQL SELECT 存在优化

Hive 宏未返回预期结果

只要它们不存在于另一个表T-SQL中,就从一个表中检索记录[重复]

使用与插入相同的变量存在的 Oracle 案例