Where子句等于一个字段,不等于另一个字段

时间:2012-09-12 20:59:04

标签: mysql sql

这是其中的一天,我无法解决这个问题。

我有以下查询:

SELECT * FROM wp_posts
JOIN wp_term_relationships ON wp_term_relationships.object_id = wp_posts.ID
WHERE term_taxonomy_id = 80

显然,这会选择类别ID 80中的所有帖子。我需要做的是选择80类但不属于类别109的所有帖子。

我已尝试过此功能,但它只选择了类别80中的相同帖子。

SELECT * FROM wp_posts
JOIN wp_term_relationships ON wp_term_relationships.object_id = wp_posts.ID
WHERE term_taxonomy_id = 80
AND term_taxonomy_id = 109

这是表结构:

wp_posts

|    ID    |
------------
|    1     |
|    2     |

wp_term_relationships

| object_id | term_taxonomy_id |
|-----------|------------------|
|     1     |       80         |
|     2     |       80         |
|     1     |       109        |

object_id与post_id匹配

查询应该只返回ID 2,因为ID 1同时是80和109。

我知道我已经完成了这一百万次,但我无法为我的生活做到这一点。有什么帮助吗?

3 个答案:

答案 0 :(得分:2)

你可以写:

SELECT *
  FROM wp_posts
  JOIN wp_term_relationships
    ON wp_term_relationships.object_id = wp_posts.ID
 WHERE term_taxonomy_id = 80
   AND wp_posts.id NOT IN
        ( SELECT object_id
            FROM wp_term_relationships
           WHERE term_taxonomy_id = 109
        )
;

(见§ 13.2.10.3 "Subqueries with ANY, IN, or SOME" in the MySQL 5.6 Reference Manual。)

答案 1 :(得分:1)

这是一种方法:

SELECT p.*
  FROM wp_posts p
  JOIN wp_term_relationships t
    ON t.object_id = p.ID AND t.term_taxonomy_id = 80
  LEFT
  JOIN wp_term_relationships n
    ON n.object_id = p.ID AND n.term_taxonomy_id = 109
 WHERE n.object_id IS NULL

这对术语关系表使用LEFT OUTER连接(别名为n),以查找类别109中的匹配行,但排除发现匹配的任何行(通过条件)在WHERE子句中,所以从wp_posts返回的行是那些不属于类别109的行。

在SQL术语中,我们将此操作称为“反连接”。

注意:如果(object_id,term_taxonomy_id)不唯一,此查询确实有可能返回“重复”行,例如,wp_term_relationships中有两行(或更多)行(object_id = 2,term_taxonomy_id = 80) 。


通常,在MySQL中,我们发现JOIN操作(包括反连接操作)通常优于子查询。

另一种替代方案(可能不会像以前的查询那样执行):

SELECT p.*
  FROM wp_posts p
 WHERE EXISTS 
       ( SELECT 1 
           FROM wp_term_relationships t
          WHERE t.object_id = p.ID 
            AND t.term_taxonomy_id = 80
        )
   AND NOT EXISTS 
       ( SELECT 1 
           FROM wp_term_relationships n
          WHERE n.object_id = p.ID 
            AND n.term_taxonomy_id = 109
        )

注意:MySQL可能会为此查询生成相同的执行计划(包括连接和反连接操作)。您需要在查询上运行EXPLAIN以查看执行计划,并测试一个是否比另一个“更快”。

还有其他方法。性能取决于可用(合适)索引,数据分布和生成的执行计划。

答案 2 :(得分:0)

您可以将此作为聚合查询执行此操作。我喜欢这种方法,因为我认为它是定义组中元素最灵活的方法:

select id
from wp_posts p JOIN
     wp_term_relationships t
     ON t.object_id = p.ID
group by id
having sum(case when term_taxonomy_id = 80 then 1 else 0 end) > 0 and    -- in 80
       sum(case when term_taxonomy_id = 109 then 1 else 0 end) = 0       -- not in 109