SQLITE: проблема тегов и продуктов


10

Я ищу способ создать запрос, чтобы сделать следующее:

Давайте рассмотрим 3 таблицы:

  • продукты: Список продуктов
  • теги: список тегов
  • tag_ties: таблица, используемая для привязки тега к товару

Давайте рассмотрим эту структуру для каждой таблицы:

Товары:

  • id (int, автоинкремент)
  • название (varchar, название продукта)

Метки:

  • id (int autoincrement)
  • ярлык (varchar, ярлык ярлыка)

Tag_ties:

  • id (int, автоинкремент)
  • tag_id (int, ссылка на идентификатор тега)
  • ref_id (int, ссылка на идентификатор продукта)

Что я хочу:

Получите все продукты, которые помечены тегами с идентификаторами 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

Ответы:


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

Подзапрос из выбранного ответа не требуется. Чтобы выбрать товары со всеми указанными идентификаторами тегов, запрос может быть простым:

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

Чтобы немного усложнить это, мы можем использовать подзапрос, чтобы смешать intersection ( AND) и union ( 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

3
Эй, ребята, спасибо, что сказали мне, что неявные объединения - это плохой стиль. Я главным образом намеревался указать, что подзапрос из выбранного ответа не был необходим. Я отредактировал ответ, чтобы использовать соединения. Если вы обнаружите что-то не так в моих запросах, пожалуйста, дайте мне знать.
Мораес

5
+1 за то, что принял отрицательный голос, не расстраиваясь, и принял во внимание совет по улучшению ваших навыков.
Зейн

2
Что сказал @Zane. +1 тоже
gbn
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.