SQL 无法让 WHERE EXISTS 子句正常工作,并且仅返回在特定日期内具有客户端类型的行

Posted

技术标签:

【中文标题】SQL 无法让 WHERE EXISTS 子句正常工作,并且仅返回在特定日期内具有客户端类型的行【英文标题】:SQL Cannot get WHERE EXISTS Clause to work properly and only return rows that have a type for a client within a certain date 【发布时间】:2019-03-08 21:00:34 【问题描述】:

好的,这让我发疯了,我相信解决方案会非常简单,我可能会把头撞到墙上。我有一个查询,我有客户数据。在某些查询中,我只希望客户在某个日期之间在该日期范围内的某个时间点有过客户访问,这对应于 Call_Report_ID 的 3、8 或 12。对于这些客户,我希望它在该日期内带回所有数据范围,而不仅仅是具有此客户访问代码的行。对于其他没有客户访问的客户,我想将他们从数据中排除。

这是我一直在玩的东西,但根本无法让它工作。

SELECT * 
FROM CV.Data AS CV 
WHERE EXISTS (SELECT * 
              FROM CV.Data AS CVD 
              WHERE CVD.Call_Report_ID IN(3,8,12) 
                  AND CVD.User_ID = 33) 
    AND CV.User_ID = 33 
    AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'

下面是我想要的示例:

Cust_ID Call_Report_ID Activity_Date
  5         3            10/15/2018
  5         7            10/28/2018
  6         9            10/21/2018
  6         11           10/25/2018 

在上面运行此查询时,我希望它返回来自客户 5 的两行,因为它们在日期范围内的任何行中的呼叫报告 ID 为 3,8 或 12,并从客户中排除这两行6,因为他们在日期范围内没有这些类型的 call_report_Id

但是,每次我运行它时,它都会返回该用户的所有行,而不仅仅是 WHERE EXISTS 子查询中指定的行。

我哪里错了?

【问题讨论】:

首先,总是缩进你的SQL。您将获得大脑性能。 抱歉,已修复,在服务器上是缩进的,只是我粘贴的时候没有 为什么不加入表本身而不是你的子查询?您能否提供一些数据样本以在 db fiddle 上进行测试。 @ArnaudPeralta - 这将导致行乘以匹配报告 ID 的数量。 您几乎肯定希望将子查询与其他一些列上的外部查询相关联——Cust_ID 一个,可能还有其他列。另外 - 不要将 BETWEEN 与日期一起使用(特别是如果数据在时间戳中) - 始终使用独占上限:AND CV.Activity_Date >= '20181001' AND CV.Activity_Date < '20190401' 【参考方案1】:

Exist 替换为in

SELECT * 
FROM Data AS CV 
WHERE Cust_ID in (SELECT Cust_ID 
              FROM Data AS CVD 
              WHERE CVD.Call_Report_ID IN(3,8,12) 
                  AND CVD.User_ID = 33) 
    AND CV.User_ID = 33 
    AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'

【讨论】:

【参考方案2】:

您没有以任何方式将子查询与外部查询连接。

SELECT * 
FROM CV.Data AS CV 
WHERE EXISTS (SELECT * 
              FROM CV.Data AS CVD 
              WHERE CVD.Call_Report_ID IN(3,8,12) 
                  AND CVD.User_ID = 33
                  AND CV.Cust_ID = CVD.Cust_ID) <--
    AND CV.User_ID = 33 
    AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'

【讨论】:

【参考方案3】:

它返回该用户的所有行,而不仅仅是在 WHERE EXISTS 子查询

这个EXISTS 不会过滤查询返回的数据。 它返回TRUEFALSE。 因此,如果它返回 FALSE,您的查询将返回 no rows 如果它在以下条件下返回TRUE 所有行

CV.User_ID = 33 AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'  

将被退回

【讨论】:

嗯,是的,但这对于可以采取什么措施来解决这个问题是相当不具体的。 不仅仅是 WHERE EXISTS 子查询中指定的那些,这就是问题所在。 OP 认为 EXISTS 过滤了行,但它没有。应该如何过滤行?这是由 OP 决定的。【参考方案4】:

它返回所有行,因为您没有在存在查询中进行任何过滤。

我认为更改此查询会更好,因此您将使用联接。

【讨论】:

连接会导致行数乘以匹配的报告 ID。【参考方案5】:

这个怎么样:

SELECT * 
FROM CV.Data AS CV 
WHERE EXISTS (SELECT * 
          FROM CV.Data AS CVD 
          WHERE CVD.Call_Report_ID IN(3,8,12) 
              AND CVD.User_ID = 33) 
AND CV.User_ID = 33 
AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'
AND CV.Call_Report_ID IN(3,8,12)

如果我是你,我会想为什么我需要这个 EXISTS 条件,它确实不是一个直接的过滤器,但是我没有足够的信息来简单地丢弃它。

您可能会将我的回答视为一个可行的提示,但请考虑一下为什么需要此 EXISTS 条件。看起来不需要它,查询可能如下所示:

SELECT * 
FROM CV.Data AS CV 
WHERE CV.User_ID = 33 
AND CV.Activity_Date BETWEEN '10/1/2018' AND '3/31/2019'
AND CV.Call_Report_ID IN(3,8,12)

【讨论】:

OP 想要所有Call_Report_IDs。如果这个查询有效,那么子查询就完全是多余的了。 @MattE - 据我了解,这个答案实际上并不能满足您的问题。 @Clockwork-Muse Ack...我太兴奋了...你是对的,它只是带回具有这些 ID 的行,而不是所有具有这些呼叫报告 ID 的行的行跨度> @Bartosz,这不起作用...它只带回具有该呼叫报告 ID 的行...我希望所有具有此客户的任何行的行都具有此呼叫报告 ID输入

以上是关于SQL 无法让 WHERE EXISTS 子句正常工作,并且仅返回在特定日期内具有客户端类型的行的主要内容,如果未能解决你的问题,请参考以下文章

Oracle where exists 子句不适用于 SQL Plus

sql面试题_SQl优化技巧_1注意通配符中like的使用,百分号放后面_2避免在where子句中对字段进行函数操作_3在子查询当中,尽量用exists代替in_4where子句中尽量不要使用(代码片

Linq to Entities 添加 Where 子句以在另一个表中查找 EXISTS

使用 where exists 子句更新多个值

如何使用 sql server exists 子句进行优化?

sql 优化方法