Запрос MySQL для выбора элементов в связанной таблице на основе И

#mysql #join #group-by #count #distinct

Вопрос:

У меня есть таблица фотографий с подробными фотографиями:

 | photoID | photoName |
| ------- | --------- |
| 1       | w         |
| 2       | x         |
| 3       | y         |
| 4       | z         |
 

и еще одна таблица tblФототЕгов тегов к фотографиям:

 | photoID | tagID |
| ------- | ----- |
| 1       | 1     |
| 1       | 2     |
| 2       | 1     |
| 3       | 2     |
| 4       | 1     |
| 4       | 2     |
 

Я пытаюсь сделать пару запросов, которые выберут фотографии с любыми заданными тегами, либо И, либо ИЛИ. В примере предположим, что я ищу фотографии, связанные с тегом 1 И/ИЛИ 2.

ИЛИ следует выбрать все фотографии (1, 2, 3 и 4).

И следует выбрать только 1 и 4.

У меня есть следующее для ИЛИ которое отлично работает:

 SELECT DISTINCT tblPhotos.photoID FROM tblPhotos 
    INNER JOIN tblPhotoTags ON tblPhotos.photoID = tblPhotoTags.photoID 
    WHERE tblPhotoTags.tagID = 1 OR tblPhotoTags.tagID = 2
 

Но я изо всех сил пытаюсь понять, как выполнить запрос И.

Комментарии:

1. A tagID может иметь только одно значение, поэтому tagID =1 AND tagID =2 не будет иметь никаких результатов. Либо свяжите второй раз с tblPhotoTags , либо используйте агрегатные функции.

Ответ №1:

Если вам нужны только идентификаторы фотографий, то нет необходимости присоединяться к tblPhotos ним .

Для 1 — го случая ( OR ) используйте DISTINCT и просто WHERE предложение:

 SELECT DISTINCT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2);
 

Для 2-го случая ( AND ) используйте агрегацию и установите условие в HAVING предложении:

 SELECT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2)
GROUP BY photoID
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
 

Если вам также нужно название фотографий, присоединяйтесь к tblPhotos :

 SELECT DISTINCT p.*
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2);
 

и:

 SELECT p.photoID, p.photoName
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2)
GROUP BY p.photoID, p.photoName
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
 

Смотрите демонстрацию.

Комментарии:

1. Чрезвычайно полезно. Для упрощения вопроса я немного сократил требования, поэтому мне все еще нужно внутреннее соединение, но затем и ПОДСЧЕТ отлично справляются с работой. Спасибо.

2. Да — все работает идеально. Еще раз спасибо.