SQLITE: Ein Problem mit Tags und Produkten


10

Ich suche nach einer Möglichkeit, eine Abfrage zu erstellen, um Folgendes zu tun:

Betrachten wir 3 Tabellen:

  • Produkte: Liste der Produkte
  • Tags: Liste der Tags
  • tag_ties: Tabelle, mit der ein Tag einem Produkt zugeordnet wird

Betrachten wir diese Struktur für jede Tabelle:

Produkte:

  • id (int, Autoincrement)
  • Name (Varchar, Name des Produkts)

Stichworte:

  • id (int Autoincrement)
  • label (varchar, label des tag)

Tag_ties:

  • id (int, Autoincrement)
  • tag_id (int, Verweis auf eine Tag-ID)
  • ref_id (int, Verweis auf eine Produkt-ID)

Was ich möchte:

Erhalten Sie beispielsweise alle Produkte, die mit den Tags ID 10, 11 und 12 gekennzeichnet sind.

Diese Abfrage funktioniert nicht, da sie die Produkte mit mindestens einem der Tags zurückgibt:

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

Antworten:


9

Versuchen Sie so etwas:

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
;

Es funktioniert :)
Julien L

11

Sie können dieses Problem mit intersect-Anweisungen lösen. Wenn Sie für jede tag_id eine separate Auswahl treffen und diese mit Schnittpunkten verknüpfen, erhalten Sie nur die Datensätze, die mit allen drei tag_ids übereinstimmen.

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

Hier ist ein Referenzartikel zur Verwendung von intersect

Sie können auch eine temporäre Ansicht verwenden, um das Erscheinungsbild zu verbessern.

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

Die Unterabfrage aus der ausgewählten Antwort wird nicht benötigt. Um Produkte mit allen angegebenen Tag-IDs auszuwählen, kann die Abfrage einfach wie folgt erfolgen:

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

Um diese Idee zu erweitern, können wir auch Abfragen basierend auf den Tag-Beschriftungen in einer einzigen Aufnahme durchführen. So wählen Sie Produkte mit den Tags aus ('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

Um es etwas zu komplizieren, können wir eine Unterabfrage verwenden, um intersection ( AND) und union ( OR) zu mischen . Die folgende Abfrage gibt Produkte mit allen Tags der Gruppe ('foo', 'bar')und mindestens einem der Tags der Gruppe zurück ('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
Du brauchst keine JOIN? Nein, technisch gesehen nicht, aber gibt es einen Grund, es nicht zu benutzen? Und zurück zur SQL-89-Notation impliziter Verknüpfungen?
Ypercubeᵀᴹ

5
Ich bin da Downvoting Sie sollten immer JOIN. stackoverflow.com/questions/5654278/… Ohne einen expliziten JOIN würde Ihr Code nicht in meinem Shop
bereitgestellt

3
Hey Leute, danke, dass ihr mir gesagt habt, dass implizite Verknüpfungen einen schlechten Stil haben. Ich wollte hauptsächlich darauf hinweisen, dass die Unterabfrage aus der ausgewählten Antwort nicht notwendig war. Ich habe die Antwort bearbeitet, um Joins zu verwenden. Wenn Sie in meinen Fragen noch etwas falsch sehen, lassen Sie es mich bitte wissen.
Moraes

5
+1 für die Ablehnung, ohne sich aufzuregen, und für die Berücksichtigung der Ratschläge zur Verbesserung Ihrer Fähigkeiten.
Zane

2
Was @Zane gesagt hat. +1 auch
gbn
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.