1

这是那些日子之一,我就是想不通。

我有以下查询:

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 中。

我知道我已经做过一百万次了,但我这辈子都无法让它发挥作用。有什么帮助吗?

4

3 回答 3

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
        )
;

(请参阅MySQL 5.6 参考手册中的第 13.2.10.3 节“使用ANYINSOME的子查询” 。)

于 2012-09-12T21:01:27.577 回答
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

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

在 SQL 用语中,我们将此操作称为“反 JOIN”。

注意:如果不是唯一的,此查询确实有可能返回“重复”行(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 以查看执行计划,并测试一个是否比另一个“更快”。

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

于 2012-09-12T21:14:04.770 回答
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
于 2012-09-12T21:24:52.640 回答