从另一个 table 中选择包含在一个集合中的行

Selecting rows that are included in a set from another table

我有一个 table "Products" 产品名称和 ID:

id    |  title
1        product 1
2        product 2

每个产品都可以有一系列标签。标记在 table "Attributes":

中标识
id |   name     | handle
1      Tag One    tag-one
2      Tag Two    tag-two
3      Tag Three  tag-three
4      Tag Four   tag-four
etc

产品标签关系是另一个 table "Tags":

id  | AttId | OwnerId
1       1        1
2       2        1
3       1        2
4       3        2
etc

好的,所以我正在尝试 select 一组产品,这些产品都至少有一个特定标签,并且可能 select 离子其他标签。这是我现在正在使用的:

SELECT products.id
FROM products
WHERE
EXISTS
( 
    SELECT  1
    FROM Tags
    INNER JOIN Attributes ON tags.AttId = Attributes.id
    WHERE Attributes.handle = 'tag-one'
    AND (
            Attributes.handle = 'tag-two'
            OR
            Attributes.handle = 'tag-four'
        )

    AND products.id = Tags.OwnerId
)

如果我删除 AND (OR) 部分,则查询有效。如上,显示没有错误,也没有结果;我应该如何写这个,这样我才能得到一组肯定有一个标签的产品,并且标签句柄有 either/or 其他指定的标签?

我喜欢使用 group byhaving 来解决这类问题 -- 因为我发现这种方法对于表达许多不同的条件非常有效。针对您的条件:

select p.*
from products p join
     tags t
     on t.OwnerId = p.id join
     attributes a
     on t.attid = a.id
group by p.id
having sum(a.handle = 'tag-one') > 0 and
       sum(a.handle in ('tag-two', 'tag-four')) > 0;

having 子句中的每个条件都会计算与条件匹配的行数(对于产品)。第一个表示至少有一行带有 'tag-one' 句柄。第二个说至少有一排有另外两个句柄。

我想如果你执行两个单独的查询并取交集,那将给你你想要的。

-- Get all the owner ids that have 'tag-one'
select OwnerId
from Tags t1
where AttId in
(
  select id
  from Attributes a1
  where a1.handle = 'tag-one'
)
intersect
-- Get all the owner ids that have tag-two and tag-four
select OwnerId
from Tags t2
where AttId in
(
  select id
  from Attributes a2
  where a2.handle in ('tag-two', 'tag-four')
)
;