SQLITE:标签和产品问题


10

我正在寻找一种创建查询以执行以下操作的方法:

让我们考虑3个表:

  • 产品:产品清单
  • 标签:标签列表
  • tag_ties:用于将标签与产品关联的表

让我们为每个表考虑以下结构:

产品:

  • id(int,自动递增)
  • 名称(varchar,产品名称)

标签:

  • id(int自动递增)
  • 标签(varchar,标签的标签)

标签:

  • id(int,自动递增)
  • tag_id(整数,引用标记ID)
  • ref_id(int,引用产品ID)

我想要的是:

获取所有带有标签ID 10、11和12的产品。

该查询不起作用,因为它返回具有至少一个标签的产品:

select 
    p.name as name,
    p.id as id
from 
    products p inner join tag_ties ties
on
    p.id=ties.ref_id
where
    ties.ref_id=p.id and
    ties.tag_id in (10,11,12)
group by 
    p.id
order by 
    p.name asc

Answers:


9

尝试这样的事情:

select
    t1.id,
    t1.name
from
    (
    select
        p.name as name,
        p.id as id
    from
        products p inner join tag_ties ties
    on
        p.id=ties.ref_id
    where
        ties.tag_id in (10,11,12)
    ) as t1
group by
    t1.id,
    t1.name
having
    count(t1.id) = 3
order by
    t1.name asc
;

它正在工作:)
Julien L

11

您可以使用相交语句解决此问题。对每个tag_id单独进行选择,并将它们与相交连接,您将仅获得与所有三个tag_id匹配的记录。

select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id
where tag_ties.tag_id = 10
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 11
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 12

这是有关使用相交的参考文章

您也可以使用临时视图使外观更好看。

create temporary view temp_view as 
select name, products.id as id, tag_ties.tag_id as tag_id 
from products join tag_ties
on tag_ties.ref_id = products.id

select name, id from temp_view where tag_id = 10
intersect ...

8

不需要来自所选答案的子查询。要选择具有所有给定标签ID的产品,查询可以很简单:

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id IN (10, 11, 12)
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

扩展这个想法,我们还可以基于单个标签中的标签查询。要选择带有标签的产品('foo', 'bar', 'baz')

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tags AS t
ON
    t.label IN ('foo', 'bar', 'baz')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

为了使它复杂一点,我们可以使用子查询来混合交集(AND)和联合(OR)。以下查询将返回具有该组的所有标签和该组('foo', 'bar')的至少一个标签的产品('baz', 'ding')

SELECT 
    p.*
FROM 
    (
    SELECT 
        p.*
    FROM 
        products AS p
    INNER JOIN 
        tags AS t
    ON
        t.label IN ('foo', 'bar')
    INNER JOIN 
        tag_ties AS tt
    ON
        tt.ref_id = p.id
    AND 
        tt.tag_id = t.id
    GROUP BY 
        p.id
    HAVING 
        COUNT(p.id)=2
    ) AS p
INNER JOIN 
    tags AS t
ON 
    t.label IN ('baz', 'ding')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id

2
您不需要JOIN吗?不,从技术上讲您不是,但是有没有理由不使用它?回到隐式联接的SQL-89表示法?
ypercubeᵀᴹ

5
我之所以投票,是因为您应该始终使用JOIN。stackoverflow.com/questions/5654278/…如果没有显式的JOIN,则您的代码将不会部署在我的商店中
gbn 2013年

3
大家好,谢谢您告诉我,隐式联接是不好的风格。我主要是要指出,从选定答案中选择子查询不是必需的。我编辑了使用联接的答案。如果您在查询中发现其他任何错误,请告诉我。
moraes

5
+1可让您在不沮丧的情况下投票,并真正考虑建议以提高您的技能。
Zane

2
@赞恩说什么。也是+1
gbn 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.