#mysql
#mysql
Вопрос:
У меня есть таблица с двумя столбцами UID
, GID
в которой существует связь GID-UID «многие к одному» (т. Е. Каждый UID может отображаться во многих строках с разными идентификаторами GID).
Если я хочу получить все UID, которые имеют определенный GID, это просто
SELECT
UID
FROM
MyTable
WHERE
GID = x
Но что, если мне нужны все UID, у которых нет определенного GID? Я придумал это:
SELECT
UID
FROM
(SELECT
UID, MAX(GID = x) AS has_gid
FROM
MyTable
GROUP BY
UID
) AS subq
WHERE
has_gid = 0
Я думаю, что это работает, но это похоже на такой взлом для такой простой проблемы. Есть ли какой-нибудь очевидный или более эффективный способ сделать это, который мне не хватает?
Комментарии:
1. Обычно способ найти строки, в которых нет строк, заключается в создании
OUTER JOIN
и фильтрацииIS NULL
.2.
what if I want all UIDs that do not have a certain GID
тогда почему бы просто не отфильтровать их, напримерselect UID from mytable WHERE GID NOT IN (x,y,z,w,...)
3. В моем случае существует более ста значений GID, и регулярно добавляются новые. Казалось бы, более правильным, чтобы запрос зависел только от одного значения.
Ответ №1:
Есть много способов написать такой запрос, т. Е. Использовать внешнее соединение и проверять выбор нулевых значений, но я думаю, что наиболее читаемым и эффективным запросом является использование функции NOT EXISTS
sql
SELECT UID
FROM MYTABLE
WHERE NOT EXISTS (
SELECT *
FROM MYTABLE T1
WHERE T1.UID = MYTABLE.UID
AND T1.GID = X
)
Комментарии:
1. Я не смог заставить этот запрос работать. Он возвращает все UID, а не только те, у которых нет GID.
2. Я думаю, что запрос работает. Я создал скрипку, чтобы продемонстрировать это: sqlfiddle.com /#!2/cc282b/8 Результат будет содержать значения
1
, и2
поскольку нет кортежей(1,4)
и(2,4)
Ответ №2:
Вы можете использовать подзапрос, подобный этому:
SELECT
UID
FROM
MyTable
WHERE
UID
NOT IN
(SELECT
distinct t.UID
FROM
MyTable t
WHERE
GID = uid_to_exclude)
Но этот запрос может выполняться быстрее:
SELECT
t1.UID
FROM
MyTable t1
LEFT JOIN
(SELECT
DISTINCT t.UID as UID2
FROM
MyTable t
WHERE
t.GID = uid_to_exclude) as t2 on t1.uid = t2.uid
WHERE t2.UID2 IS NULL
Комментарии:
1. Для меня не очевидно, какой метод будет более эффективным. Оба включают подзапрос, и я могу представить, что
IN
это очень дорого.2. Я добавил новый запрос, который выполняется быстрее.
3. Этот запрос намного медленнее, чем в моем вопросе. Мне требуется около минуты, чтобы выбрать 5 миллионов идентификаторов UID из 150 миллионов пар (UID, GID). Ваш мне пришлось убить после запуска около 20 минут.