SQLITE: problem z tagami i produktami


10

Szukam sposobu na utworzenie zapytania, aby wykonać następujące czynności:

Rozważmy 3 tabele:

  • produkty: lista produktów
  • tagi: lista tagów
  • tag_ties: tabela używana do powiązania tagu z produktem

Rozważmy tę strukturę dla każdej tabeli:

Produkty:

  • id (int, autoinkrement)
  • nazwa (varchar, nazwa produktu)

Tagi:

  • id (int autoincrement)
  • etykieta (varchar, etykieta tagu)

Tag_ties:

  • id (int, autoinkrement)
  • tag_id (int, odniesienie do identyfikatora tagu)
  • ref_id (int, odniesienie do identyfikatora produktu)

Czego chcę:

Uzyskaj wszystkie produkty oznaczone na przykład tagami id 10, 11 i 12.

To zapytanie nie działa, ponieważ zwraca produkty posiadające co najmniej jeden z tagów:

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

Odpowiedzi:


9

Wypróbuj coś takiego:

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
;

Działa :)
Julien L

11

Możesz rozwiązać ten problem za pomocą instrukcji przecięcia. Dokonaj osobnego wyboru dla każdego tag_id i połącz je przecinkami, a otrzymasz tylko rekordy, które pasują do wszystkich trzech 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

Oto artykuł referencyjny na temat używania przecinania

Możesz także użyć tymczasowego widoku, aby wyglądał trochę ładniej.

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

Podzapytanie z wybranej odpowiedzi nie jest potrzebne. Aby wybrać produkty ze wszystkimi podanymi identyfikatorami tagów, zapytanie może być po prostu:

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

Rozszerzając ten pomysł, możemy również wyszukiwać w oparciu o etykiety znaczników w jednym ujęciu. Aby wybrać produkty z tagami ('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

Aby to trochę skomplikować, możemy użyć podzapytania, aby połączyć przecięcie ( AND) i union ( OR). Poniższe zapytanie zwróci produkty ze wszystkimi tagami grupy ('foo', 'bar')i co najmniej jednym z tagów grupy ('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
Nie potrzebujesz JOIN? Nie, technicznie nie, ale czy jest jakiś powód, aby go nie używać? A wracając do notacji SQL-89 o niejawnych połączeniach?
ypercubeᵀᴹ

5
Oddaję głos, ponieważ zawsze powinieneś używać JOIN. stackoverflow.com/questions/5654278/... Bez wyraźnego DOŁĄCZENIA, twój kod nie zostałby wdrożony w moim sklepie
gbn 18.04.13

3
Cześć wszystkim, dziękuję, że powiedzieliście mi, że ukryte połączenia są złym stylem. Chciałem przede wszystkim podkreślić, że podzapytanie z wybranej odpowiedzi nie było konieczne. Zredagowałem odpowiedź, aby użyć sprzężeń. Jeśli zauważysz coś jeszcze nie tak w moich zapytaniach, daj mi znać.
moraes 18.04.13

5
+1 za wzięcie udziału w głosowaniu bez denerwowania i wzięcie pod uwagę porady dotyczącej poprawy swoich umiejętności.
Zane

2
Co powiedział @Zane. +1 też
gbn 18.04.13
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.