【问题标题】:Complicated Join Ignoring 'WHERE EXISTS'复杂的连接忽略'WHERE EXISTS'
【发布时间】:2014-05-25 15:12:29
【问题描述】:

我需要检查 USICOAL 主数据库中的所有促销活动,但不在快照中(简单):

SELECT U.[PROMOTION_NO]
      ,U.[STORE_NO]
      ,U.[PROMOTION_NAME]
      ,U.[SCHED_BGN_DATETIME] AS 'USICOAL START_DATE'
      ,U.[SCHED_END_DATETIME] AS 'USICOAL END_DATE'
      ,S.[SCHED_BGN_DATETIME] AS 'SNAPSHOT START_DATE'
      ,S.[SCHED_END_DATETIME] AS 'SNAPSHOT END_DATE'
FROM [REWARDS_SNAPSHOT_2471].[dbo].[PROMOTION] AS S
FULL OUTER JOIN [USICOAL].[dbo].[PROMOTION] AS U
ON S.PROMOTION_NO = U.PROMOTION_NO

但是USICOAL 数据库没有显示正确的STORE_NO(即'8882'),而是将有一个随机数链接在一个单独的表(STORE_GROUP_STORE)上,所以我有以下查询:

SELECT UP.STORE_NO
       ,UP.PROMOTION_NO
FROM [USICOAL].[dbo].[PROMOTION] AS UP
LEFT JOIN [USICOAL].[dbo].[STORE_GROUP_STORE] AS US
ON UP.STORE_NO = US.STORE_GROUP_ID
WHERE US.STORE_NO = '8882'

以上两项都单独工作,但最重要的是包括不在下面查询中的商店('8882'),所以我尝试将它们链接在一起,查询似乎忽略了第二部分:

SELECT U.[PROMOTION_NO]
      ,U.[STORE_NO]
      ,U.[PROMOTION_NAME]
      ,U.[SCHED_BGN_DATETIME] AS 'USICOAL START_DATE'
      ,U.[SCHED_END_DATETIME] AS 'USICOAL END_DATE'
      ,S.[SCHED_BGN_DATETIME] AS 'SNAPSHOT START_DATE'
      ,S.[SCHED_END_DATETIME] AS 'SNAPSHOT END_DATE'
FROM [REWARDS_SNAPSHOT_2471].[dbo].[PROMOTION] AS S
FULL OUTER JOIN [USICOAL].[dbo].[PROMOTION] AS U
ON S.PROMOTION_NO = U.PROMOTION_NO

WHERE EXISTS

(SELECT UP.STORE_NO
       ,UP.PROMOTION_NO
FROM [USICOAL].[dbo].[PROMOTION] AS UP
LEFT JOIN [USICOAL].[dbo].[STORE_GROUP_STORE] AS US
ON UP.STORE_NO = US.STORE_GROUP_ID
WHERE US.STORE_NO = '8882')

AND S.PROMOTION_NO IS NULL
OR U.SCHED_BGN_DATETIME != S.SCHED_BGN_DATETIME
OR U.SCHED_END_DATETIME != S.SCHED_END_DATETIME

我知道上面很复杂,但是由于数据库结构我想不出如何简化它。

【问题讨论】:

    标签: sql-server tsql join exists


    【解决方案1】:

    我认为这是增加额外结果的一点

    AND S.PROMOTION_NO IS NULL
    OR U.SCHED_BGN_DATETIME != S.SCHED_BGN_DATETIME
    OR U.SCHED_END_DATETIME != S.SCHED_END_DATETIME
    

    您可能希望根据您的逻辑执行此操作

        AND (S.PROMOTION_NO IS NULL
    OR U.SCHED_BGN_DATETIME != S.SCHED_BGN_DATETIME
    OR U.SCHED_END_DATETIME != S.SCHED_END_DATETIME)
    

    【讨论】:

      【解决方案2】:

      您已经将外部联接重新置于前面。要在 U 中而不是 S 中查找行,请从 U 中选择左连接 S:

      SELECT U.[PROMOTION_NO]
            ,U.[STORE_NO]
            ,U.[PROMOTION_NAME]
            ,U.[SCHED_BGN_DATETIME] AS 'USICOAL START_DATE'
            ,U.[SCHED_END_DATETIME] AS 'USICOAL END_DATE'
            ,S.[SCHED_BGN_DATETIME] AS 'SNAPSHOT START_DATE'
            ,S.[SCHED_END_DATETIME] AS 'SNAPSHOT END_DATE'
      FROM [USICOAL].[dbo].[PROMOTION] AS U
      LEFT JOIN [REWARDS_SNAPSHOT_2471].[dbo].[PROMOTION] AS S
        ON S.PROMOTION_NO = U.PROMOTION_NO
      WHERE S.PROMOTION_NO IS NULL
      

      这似乎违反直觉; S.PROMOTION_NO怎么能等于主表中的键为空?

      答案是在进行连接时评估连接条件。但是在进行连接之后评估 where 子句,并且当左连接未命中时,连接表中的所有列都为空。因此,要查找所有 错过的 联接,请通过仅保留联接表中具有空值的结果来过滤联接结果。

      【讨论】:

      • 非常感谢大家的帮助!我终于有了工作脚本,并且难以置信地重温了一遍,这将使我们的生活变得更加轻松。 - 谢谢!
      猜你喜欢
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-15
      • 2018-06-18
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多