Проблема с запросами «многие ко многим» в MySQL - PullRequest
11 голосов
/ 09 февраля 2010

Вот моя проблема. У меня есть таблица «многие ко многим» под названием «user_has_personalities». В моем приложении пользователи могут иметь много личностей, а личность может принадлежать многим пользователям.

Таблица содержит два целочисленных столбца: user_id и personal_id.

Что мне нужно сделать, это получить всех пользователей, у которых есть хотя бы все личности (набор personal_ids переменного размера), которые я предоставляю для запроса.

Например, я хотел бы получить всех пользователей, которые имеют личность с идентификаторами 4, 5, 7, но могут также иметь некоторых других личностей. Но мне нужен запрос для работы с переменным числом желаемых идентификаторов личности, например, 4, 5, 7, 9, 10.

Есть идеи?

Ответы [ 3 ]

6 голосов
/ 09 февраля 2010

Этот запрос выполняет работу:

select  user_id
from    user_has_personalities
where   personality_id in (<list-of-personality-ids>)
group by user_id
having count(*) = <numer-of-items-in-IN-list>

Вам необходимо предоставить список идентификаторов личности через запятую для <list-of-personality-ids>, а также указать количество предметов в списке элиты. Придерживаясь вашего примера, вы получите:

select  user_id
from    user_has_personalities
where   personality_id in (4,5,7)
group by user_id
having count(*) = 3

это гарантирует, что вы получите только тех пользователей, у которых есть все эти личности.

4 голосов
/ 09 февраля 2010
SELECT  *
FROM    (
        SELECT  DISTINCT user_id
        FROM    user_has_personalities
        ) uhpo
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    user_has_personalities uhpi
        WHERE   uhpi.user_id  = uhpo.user_id
                AND personality_id IN (4, 5, 6, 9, 10)
        LIMIT 1 OFFSET 4
        )

Значение смещения должно быть на 1 меньше количества элементов в списке IN.

Если у вас есть личный список в отдельной таблице, используйте это:

SELECT  *
FROM    (
        SELECT  DISTINCT user_id
        FROM    user_has_personalities
        ) uhpo
WHERE   (
        SELECT  COUNT(*)
        FROM    perslist p
        JOIN    user_has_personalities uhpi
        ON      uhpi.user_id = uhpo.user_id
                AND uhpi.personality_id = p.id
        ) =
        (
        SELECT  COUNT(*)
        FROM    perslist
        )

Чтобы это работало правильно (и быстро), вам нужно иметь индекс UNIQUE для user_has_personalities (user_id, personality_id) (в этом порядке).

Если у вас есть таблица users, и почти у всех пользователей есть запись в user_has_personalities, то подставьте ее вместо вложенного запроса DISTINCT:

SELECT  user_id
FROM    users uhpo
WHERE   (
        SELECT  COUNT(*)
        FROM    perslist p
        JOIN    user_has_personalities uhpi
        ON      uhpi.user_id = uhpo.user_id
                AND uhpi.personality_id = p.id
        ) =
        (
        SELECT  COUNT(*)
        FROM    perslist
        )
1 голос
/ 09 февраля 2010
SELECT a.user_id
FROM user_has_personalities a
JOIN user_has_personalities b ON a.user_id = b.user_id AND b.personality_id = 5
JOIN user_has_personalities c ON a.user_id = c.user_id AND b.personality_id = 7
WHERE a.personality_id = 4

Было бы достаточно легко сгенерировать этот список программно, но это не так просто, как предоставить набор. С другой стороны, это эффективно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...