SQLITE:タグと製品の問題


10

次のことを行うクエリを作成する方法を探しています。

3つのテーブルについて考えてみましょう。

  • 製品:製品リスト
  • タグ:タグのリスト
  • tag_ties:タグを製品に関連付けるために使用されるテーブル

各テーブルについてこの構造を考えてみましょう:

製品:

  • id(int、autoincrement)
  • 名前(varchar、製品名)

タグ:

  • id(int自動インクリメント)
  • ラベル(varchar、タグのラベル)

Tag_ties:

  • id(int、autoincrement)
  • tag_id(int、タグIDへの参照)
  • ref_id(int、製品IDへの参照)

私が欲しいもの:

たとえば、タグID 10、11、および12でタグ付けされたすべての製品を取得します。

このクエリは機能しません。少なくとも1つのタグを持つ製品が返されるためです。

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

回答:


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ごとに個別の選択を行い、それらを交差と結合すると、3つの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')少なくとも1つのタグを持つ商品を返します('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

3
やあみんな、暗黙の結合は悪いスタイルだと言ってくれてありがとう。私は主に、選択した回答からのサブクエリは必要ないことを指摘するつもりでした。結合を使用するように回答を編集しました。私のクエリで何か他の問題を見つけたら、私に知らせてください。
moraes 2013

5
怒ることなく反対投票を行い、実際にアドバイスを参考にしてスキルを向上させるための+1。
ゼーン2013

2
@ゼーンが言ったこと。+1も
gbn 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.