SQL: Выберите * где атрибут соответствует всем элементам в массиве

#sql #arrays #select

#sql #массивы #выберите

Вопрос:

Работая в приложении Rails, у меня есть следующая структура таблицы (только соответствующие столбцы)

Фотографии (идентификатор: целое число) Теги (photo_id: целое число, tag_id: целое число) Теги (идентификатор: целое число, имя: строка)

У меня есть следующий SQL-запрос:

 SELECT distinct photos.* 
FROM "photos" INNER JOIN "taggings" ON "photos"."id" = "taggings"."photo_id" 
                INNER JOIN "tags"     ON "tags"."id" = "taggings"."tag_id" 
WHERE "tags"."name" IN ('foo', 'bar')
  

Когда я генерирую этот запрос, я передаю массив тегов (в данном случае ["foo","bar"] ). Запрос правильно выполняет поиск фотографий, которые соответствуют ЛЮБОМУ из тегов, переданных в массиве.

Как я могу изменить этот запрос, чтобы выбирать записи со ВСЕМИ заданными тегами (т. Е. Фотография соответствует, только если помечена «foo» И «bar», вместо выбора записей с ЛЮБЫМ из заданных тегов?

Ответ №1:

Может быть лучший способ, но это должно сработать

 SELECT photos.id,max(otherColumn)
FROM "photos" 
INNER JOIN "taggings"
ON "photos"."id" = "taggings"."photo_id" 
INNER JOIN "tags" 
ON "tags"."id" = "taggings"."tag_id" 
WHERE "tags"."name" IN ('foo', 'bar')
group by photos.id
having count(*) = 2 --2 is the number of items in your array of tags.
  

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

1. Это работает, но в PostgreSQL я постоянно сталкиваюсь с классической «Ошибкой PG: столбец ______ должен быть включен в предложение Group By или использоваться в агрегатной функции». Я могу избежать этого, сгруппировав по всем столбцам, но знаете ли вы лучшее решение?

Ответ №2:

Если вы используете rails, вам не нужен запрос для этого.

Tags.find(1).taggings должен предоставить вам массив всех фотографий с этим тегом

 you can also use Tags.find_by_name("foo").taggings
  

вы можете аналогичным образом выполнить итерацию по всем тегам и собрать массивы, а затем просто сделать что-то подобное с имеющимися у вас массивами.

 [ 1, 1, 3, 5 ] amp; [ 1, 2, 3 ]   #=> [ 1, 3 ]
  

В основном ‘и’ массивы и получите уникальные фотографии.Таким образом, вы можете получить фотографии, соответствующие всем тегам.

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

1. Не очень хорошая идея, поскольку для этого требуется несколько вызовов базы данных и потенциально возврат большого количества данных в память. Конечно, это может быть хорошо для небольшого набора данных и небольшого числа пользователей.

2. Нет, это не сработает. Я использую это для создания метода поиска по фотографиям, который я могу связать с другими методами. Он должен исходить из фотографий, чтобы его можно было ограничить и т.д.