Выберите столбцы, которые не отображаются с другим значением столбца

#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 минут.