SQL 排除匹配所有多个条件的行

Posted

技术标签:

【中文标题】SQL 排除匹配所有多个条件的行【英文标题】:SQL exclude rows matching all of multiple criteria 【发布时间】:2017-05-21 15:52:07 【问题描述】:

我目前有一个合并两个表以创建一个新表进行分析的查询。在尝试绘制图表以进行演示时得到一些有趣的结果后,我了解到其中一些是从未清理过的假数据。我已经能够识别出导致问题的数据,并且为了节省时间,我希望将其排除在查询中,以便继续进行分析。

这个假数据符合所有这些条件:

rate_type = 标准 client_net_cleared = 0 程序为空白(非 Null)

我在 SELECT 中使用 CASE 语句标识了这些,但意识到要使用它,我必须执行另一个表,查询该表中的所有内容减去根据 CASE 语句确定为符合上述条件的内容。一定有比这更好的解决方案。

我目前正试图将这些排除在 WHERE 语句中,但阅读了其他问题主题后发现 WHERE 不太擅长管理多个子条件。

我有什么:

SELECT *
, CASE WHEN tad.rate_type = 'Standard'
    AND tad.client_net_cleared = '0'
    AND program= '' THEN 1
    ELSE '0'
    END AS noise

FROM tableau.km_tv_ad_data_import tad
JOIN tableau.km_tv_ad_report ga
    ON ga.session_timestamp >= tad.timestamp - INTERVAL '4 minute'
    AND ga.session_timestamp <= tad.timestamp + INTERVAL '5 minute'
    AND ga.session_timestamp != tad.timestamp

WHERE tad.timestamp >= '2016-09-01'
AND (tad.rate_type != 'Standard'
    AND tad.client_net_cleared != '0'
    AND tad.program != '')

GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21

样本数据集:

 timestamp           | rate_type | program         | client_net_cleared | noise
---------------------|-----------|-----------------|--------------------|-------
 2016-11-01 18:00:00 | Standard  | Diving          |                 50 | 0
 2016-12-01 21:00:00 | Holiday   | Classic Albums  |                100 | 0
 2016-11-01 09:00:00 | FireSale  | Panorama        |                  0 | 0
 2016-10-01 12:00:00 | Standard  |                 |                  0 | 1
 2016-12-01 15:00:00 | Holiday   | MythBusters     |                100 | 0
 2016-10-01 13:00:00 | FireSale  | House           |                200 | 0

我需要什么:

排除符合所有三个条件的行:rate_type = Standard、client_net_cleared = 0、program 为空(非 Null)。

【问题讨论】:

你试过嵌套表吗,比如下一个:-select * from ( -- Put your query here ) a where rate_type = Standard and client_net_cleared = 0 and program is not Null 您不能按序号位置分组(至少不能在 sql-server 中)。如果你可以在 mysql 中,这是一个习惯,你应该立即停止。 尤其是在使用SELECT * 时。这使得它依赖于CREATE TABLE 语句中列的顺序。我感觉他实际上是按所有列分组的,所以应该只是SELECT DISTINCT * @SeanLange 有什么更好的分组方式?如果有的话,我很乐意使用更短或更灵活的分组方式! 更好的方法是命名列。如果您更改表(或天堂禁止实际命名列而不是使用 *)并且您按序号位置分组,则您的查询被破坏。修复它变成了一场噩梦。 【参考方案1】:

正确的标准是

AND NOT (tad.rate_type = 'Standard'
        AND tad.client_net_cleared = '0'
        AND tad.program = '')

deMorgan's Law 相当于:

AND (tad.rate_type != 'Standard'
    OR tad.client_net_cleared != '0'
    OR tad.program != '')

这与您的查询类似,但请注意它使用的是OR,而不是AND

【讨论】:

但是 OP 说明了所有三个条件都满足的地方......你的第二个陈述否定了这一点,因为只有一个需要等同于真实,或者我错过了什么? @scsimon 请注意,我也否定了标准。这就是德摩根定律:NOT (x AND y) 等价于 (NOT x OR NOT y) 没关系,我现在明白了。谢谢你的教育 @Barmar 这行得通,谢谢!现在我也了解了德摩根定律。【参考方案2】:

您还可以在 WHERE 子句中执行 SELECT 以使用 NOT IN 排除行。例如,一个供应商的所有资格和不在不包括具有其他供应商资格的人:

select * from qualification q
inner join certification c on c.id = q.certificationid
    where  c.vendorid = 3 and 
    employeeid not in 
    (    
        select employeeid from qualification q
        inner join
        certification c on c.id = q.certificationid
        where c.vendorid <> 3
    )  
 

【讨论】:

以上是关于SQL 排除匹配所有多个条件的行的主要内容,如果未能解决你的问题,请参考以下文章

SQL:如果两个条件都满足而不是在多个where中单独排除,如何仅排除条件?

存在匹配时排除不匹配行的 SQL 多对多连接

sql中left join on 多个条件需要特殊注意之处

根据多个筛选条件 - SQL访问排除记录

SQL查询;如果子记录 = 条件则排除记录

PHP