返回所有子集中存在的不同ID列表

时间:2012-03-23 17:04:10

标签: sql postgresql-9.0

我有两张桌子

Table "public.tags_to_entities"
 Column |  Type   | Modifiers 
--------+---------+-----------
 tid    | integer | not null
 eid    | integer | not null

   Table "public.tag_tree"
 Column |  Type   | Modifiers 
--------+---------+-----------
 tid    | integer | not null
 pid    | integer | not null
 level  | integer | 

tag_tree包含标记之间的所有关系,这意味着SELECT pid FROM tag_tree WHERE tid = ?将返回该标记的父级。 level列仅存在或ORDER BY

我想返回在每个标记子集中至少有一个标记的所有eid的列表。使用以下查询执行一个子集

SELECT DISTINCT eid
FROM tags_to_entities
WHERE
    tags_to_entities.tid = 1 OR
    tags_to_entities.tid IN (SELECT tag_tree.tid FROM tag_tree WHERE tag_tree.pid = 1));

这将返回标记1中存在的所有eid或其子标记之一。如果我想要返回与eid 1相关的至少一个代码中存在的所有2。到目前为止我失败的方法是

SELECT DISTINCT eid
FROM tags_to_entities
WHERE
    (
        tags_to_entities.tid = 1 OR
        tags_to_entities.tid IN (SELECT tag_tree.tid FROM tag_tree WHERE tag_tree.pid = 1)) AND
    (
        tags_to_entities.tid = 2 OR
        tags_to_entities.tid IN (SELECT tag_tree.tid FROM tag_tree WHERE tag_tree.pid = 2));

这不起作用,因为tid不能同时为1和2。我怎么解决这个问题? (eid将在稍后的条目表中加入)

1 个答案:

答案 0 :(得分:1)

您需要使用GROUP BY代替DISTINCT。这允许您使用聚合函数和HAVING子句。

SELECT
  map.eid
FROM
  tags_to_entities    AS map
INNER JOIN
  tag_tree            AS tree
    ON map.tid = tree.tid
WHERE
     (tree.tid = 1 OR tree.pid = 1)
  OR (tree.tid = 2 OR tree.pid = 2)
GROUP BY
  map.id
HAVING
  COUNT(DISTINCT CASE WHEN (tree.tid = 1 OR tree.pid = 1) THEN 1
                      WHEN (tree.tid = 2 OR tree.pid = 2) THEN 2
                 END)
  = 2

JOINWHERE子句获取标记为1 2的所有实体。但是,然后将它们组合在一起,然后计算这些标记所在的不同类别。只有当它为2时,实体才能通过HAVING子句。