выберите элементы с тегами с идентификаторами 1 и 2, но не с идентификаторами 3 или 4 - PullRequest
0 голосов
/ 04 мая 2019

Я имею отношение к вопросу Выбор элемента, соответствующего нескольким тегам , где его спросили, как выбрать элементы с тегами с идентификаторами 1 и 2.

Данный ответ работаетотлично.

Но что, если мне нужны все элементы с тегами 1 и 2, но не с тегами 3 ИЛИ 4?

Возможно ли это сделать одним запросом?Я не могу понять: - (

Так что это мой код для выбора видеофайлов с тегами с идентификаторами 155 и 91 в таблице tags_map:

SELECT DISTINCT
    vf.id,
    vf.title,
    vf.filename
FROM video_files vf
JOIN tags_map tm ON tm.video_file_id = vf.id
    AND tm.tag_id IN (155,91)
GROUP BY vf.id
HAVING COUNT(DISTINCT tm.tag_id) = 2 ORDER BY id ASC;

Возможно ли этоизменить это?

Извините, да, название вопроса было неясным / неправильным. Я исправил его.

Я постараюсь прояснить:

item 1: has tags with ids 1 -> Not enough, I don't want to see it
item 2: has tags with ids 1 and 2 -> I do want to see it
item 3: has tags with ids 1, 2 and 3 -> It has tag with id 3 in it, I don't want to see it
item 4: has tags with ids 1, 2 and 4 -> It has tag with id 4 in it, I don't want to see it
item 5: has tags with ids 1, 2, 3 and 4 -> It has tags with id 3 and/or 4 in it, I don't want to see it

Ответы [ 4 ]

1 голос
/ 04 мая 2019

Вы можете использовать условное агрегирование:

select item
from itemtags
group by item
having sum(tag = 1) > 0 and
       sum(tag = 2) > 0 and
       sum(tag = 3) = 0 and
       sum(tag = 4) = 0;
0 голосов
/ 05 мая 2019

Этот должен вместо этого сделать (и быть совместимым с MySQL):

SELECT DISTINCT vf.id,
                vf.title,
                vf.filename

           FROM video_files vf

           JOIN tags_map ti  -- Tags In  (included)
             ON ti.video_file_id = vf.id
            AND ti.tag_id IN (1,2)

LEFT OUTER JOIN tags_map te  -- Tags Out (excluded)
             ON te.video_file_id = vf.id
            AND te.tag_id IN (3,4)

       GROUP BY vf.id,
                vf.title,
                vf.filename

         HAVING count(DISTINCT ti.tag_id) = 2
            AND count(DISTINCT te.tag_id) = 0
0 голосов
/ 04 мая 2019

Есть много способов сделать это, но, на мой взгляд, лучшим остается EXCEPT для этой ситуации:

SELECT DISTINCT
    vf.id,
    vf.title,
    vf.filename
FROM video_files vf
WHERE vf.id IN
(

    SELECT vf.id
      FROM video_files vf
      JOIN tags_map tm
        ON tm.video_file_id = vf.id
       AND tm.tag_id IN (1,2)
  GROUP BY vf.id
    HAVING count(tm.tag_id) >= 2

    EXCEPT

    SELECT vf.id
      FROM video_files vf
      JOIN tags_map tm
        ON tm.video_file_id = vf.id
       AND tm.tag_id IN (3,4)
)

Преимущество здесь в том, что вы можете иметь произвольно длинный список тегов в обоих случаях (включенных и исключенных). Просто обновите счетчик включенных тегов, если вы это сделаете (в противном случае нам нужно усложнить запрос, чтобы убедиться, что выбран только идентификатор видео, который соответствует ВСЕМ тегам).

0 голосов
/ 04 мая 2019

В случае, если вы не хотите 3 и 4 , вам нужно только проверить значения тегов min и max:

select item
from itemtags
where tag in (1, 2, 3, 4)
group by item
having min(tag) = 1 and max(tag) = 2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...