Запрос бы сделать

Hett

Есть таблица "Пользователи", и есть таблица "Вещи". Между ними связь многие-ко-многим. Нужно выбрать пользователей имеющих определенные вещи одновременно.
В общем путей много вижу, например можно сгруппировать по ID и поглядеть в HAVING количество записей в группировке.Но как узнать количество этих записей? Проблема еще в том, что используется ОРМ и использование подзапросов затруднено.
24 ответа

Hett

Но как узнать количество этих записей?
Не понял в чем вопрос. В функции COUNT(*) ? Или в том, что сравнивать ее результат нужно с количеством "определенных вещей" ?


Hett

Читай про реляционное деление.


Hett

Или в том, что сравнивать ее результат нужно с количеством "определенных вещей" ?
Пусть есть вещи А, Б и В.Нужно выбрать пользователей которые имеют все эти 3 вещи.


Hett

Читай про реляционное деление.
Что конкретно?


Hett

Что конкретно?
Все конкретно. Там того деления-то - два вложенных друг в друга [NOT] EXISTS-а...


Hett

Пусть есть вещи А, Б и В.Нужно выбрать пользователей которые имеют все эти 3 вещи.
В этом случае вообще все просто: выбрать всех пользователей, у которых есть вещи из списка, сгруппировать по пользователю, посчитать количество уникальных вещей пользователя, взять лишь тех пользователей, у которых количество уникальных вещей равно кол-ву вещей в списке.Для решения нужно IN, GROUP BY + COUNT(distinct ...), HAVING


Hett

Hett,Два подзапроса с exist либо два join-на с distinct.


Hett

В этом случае вообще все просто: выбрать всех пользователей, у которых есть вещи из списка, сгруппировать по пользователю, посчитать количество уникальных вещей пользователя, взять лишь тех пользователей, у которых количество уникальных вещей равно кол-ву вещей в списке.Для решения нужно IN, GROUP BY + COUNT(distinct ...), HAVING
Всё вышеперечисленное не нужно.


Hett

можно сгруппировать по ID и поглядеть в HAVING количество записей в группировке.
Я так и не понял, что вам мешает реализовать этот сценарий.
SELECT пользователи.*
FROM пользователи,
 (SELECT ID_пользователя FROM связь WHERE ID_вещи IN (ID_А,ID_Б,ID_В) GROUP BY ID_пользователя HAVING COUNT(*)=3) t
WHERE пользователи.ID=t.ID_пользователя
Если у пользователя одна вещь может быть несколько раз (несколько записей в таблице связи), то COUNT(*) заменить на COUNT(DISTINCT ID_вещи)


Hett

Всё вышеперечисленное не нужно
для решения задачи - сгодится...Ну а взаимозаменяемость IN / EXISTS / JOIN - совсем другая тема для разговора. Надо будет автору - сам разберется с нею.


Hett

Hett,Два подзапроса с exist либо два join-на с distinct.
Технически можно и так, но плохо масштабируемо при росте количества "общих" вещей.


Hett

Я так и не понял, что вам мешает реализовать этот сценарий.
SELECT пользователи.*
FROM пользователи,
 (SELECT ID_пользователя FROM связь WHERE ID_вещи IN (ID_А,ID_Б,ID_В) GROUP BY ID_пользователя HAVING COUNT(*)=3) t
WHERE пользователи.ID=t.ID_пользователя
Если у пользователя одна вещь может быть несколько раз (несколько записей в таблице связи), то COUNT(*) заменить на COUNT(DISTINCT ID_вещи)
Вопрос был как раз в том, как это сделать без подзапроса. Если честно уже нашел в ОРМ возможность делать подзапросы. :)


Hett

для решения задачи - сгодится...Ну а взаимозаменяемость IN / EXISTS / JOIN - совсем другая тема для разговора. Надо будет автору - сам разберется с нею.
Будь добр, напиши запрос без подзапросов.


Hett

Вопрос был как раз в том, как это сделать без подзапроса.
Подзапрос можно раскрыть, но производительность запроса наверняка упадет.


Hett

Подзапрос можно раскрыть, но производительность запроса наверняка упадет.
Предыдущий мой пост был не тебе, а Добрый Э - Эх., если че)Запрос на получение юзеров я без труда написал (сначала джоиним, потом группируем потом смотрим количество свопадений). Но получить количество пользователей я не смог.


Hett

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


Hett

Будь добр, напиши запрос без подзапросов.
Да что тут писать-то...
SELECT пользователи.*
FROM пользователи, связь t1, связь t2, связь t3 
WHERE пользователи.ID=t1.ID_пользователя AND t1.ID_вещи=ID_А
 AND пользователи.ID=t2.ID_пользователя AND t2.ID_вещи=ID_Б
 AND пользователи.ID=t3.ID_пользователя AND t3.ID_вещи=ID_В
SELECT пользователи.*
FROM пользователи
WHERE EXISTS (SELECT NULL FROM связь WHERE ID_вещи=ID_А)
 AND EXISTS (SELECT NULL FROM связь WHERE ID_вещи=ID_Б)
 AND EXISTS (SELECT NULL FROM связь WHERE ID_вещи=ID_В)


Hett

А если вещей 100, то 100 джоинов/подзапросов делать?


Hett

Предыдущий мой пост был не тебе, а Добрый Э - Эх., если че)
Прошу прощения, если необоснованно вмешался. Но мы тут решаем конкретную техническую задачу, а не выясняем кто может или не может написать запрос.


Hett

А если вещей 100, то 100 джоинов/подзапросов делать?
Да. И о том, что такой метод не очень хорош я уже говорил.
Технически можно и так, но плохо масштабируемо при росте количества "общих" вещей.


Hett

2 ТСТестовые данные, точную формулировку поставленной задачи и требуемый результат на приведенных тестовых данных давай. Тогда будут конкретные решения.


Hett

2 ТСТестовые данные, точную формулировку поставленной задачи и требуемый результат на приведенных тестовых данных давай. Тогда будут конкретные решения.
+1, а то такие вот перлы
можно сгруппировать по ID и поглядеть в HAVING количество записей в группировке.Но как узнать количество этих записей?
напрягают :)


Hett

SELECT пользователи.*
FROM пользователи
INNER JOIN таблица_связей
WHERE таблица_связей.айди_вещи IN (1,2,3)
GROUP BY пользователи.айди
HAVING(COUNT(*) = 3)


Hett

так я получаю нужные мне записи, вопрос в том, как узнать их количество. Могу сделать тестовых данных чуть позже.