171

Вопрос по sql, mysql – MySQL «НЕ В» запрос

Я хотел выполнить простой запрос, чтобы выбросить все строкиTable1 где значение основного столбца отсутствует в столбце другой таблицы (Table2).

Я пытался с помощью:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

Вместо этого это вызывает синтаксическую ошибку. Поиск Google привел меня на форумы, где люди говорили, что MySQL не поддерживаетNOT IN и нужно использовать что-то чрезвычайно сложное. Это правда? Или я совершаю ужасную ошибку?

<span>А что, если мне нужны похожие данные из трех таблиц. Я имею в виду, что одна таблица1 имеет 2000 записей, две другие таблицы 2 &amp;3 из них имеют, скажем, 500 записей, все они имеют общее поленазвание&#39;, Как мы можем получить все детали из таблицы 1, которых нет в таблице 2 &amp;3 на основеназвание&#39;, Можем ли мы использовать NOT IN дважды, если да, то как?</span>

Aug 03, 2011, 5:16 AMотuser875913

5ответов

5

Будь остороженNOT IN не псевдоним для<> ANY, но для !<> ALL

http://dev.mysql.com/doc/refman/5.0/en/any-in-some-subqueries.html

SELECT c FROM t1 LEFT JOIN t2 USING (c) WHERE t2.c IS NULL

косяк» заменить на

SELECT c FROM t1 WHERE c NOT IN (SELECT c FROM t2)

Вы должны использовать

SELECT c FROM t1 WHERE c <> ANY (SELECT c FROM t2)
35

НЕ В, против НЕ СУЩЕСТВУЕТ, ПРОТИВ ЛЕВОГО СОЕДИНЕНИЯ / НУЛЬ В MySQL

MySQL, как и все другие системы, кроме SQL Server, может оптимизировать /LEFT JOINIS NULL возвращатьFALSE как только найдено соответствующее значение, и это единственная система, которая позаботилась о документировании этого поведения. [...] Поскольку MySQL не может использоватьHASH а такжеMERGE алгоритмы объединения, единственныйANTI JOIN на это способен […]NESTED LOOPS ANTI JOIN

По сути, []NOT IN точно такой же план, что /LEFT JOINIS NULL использует, несмотря на то, что эти планы выполняются различными ветвями кода, и они выглядят по-разному в результатахEXPLAIN, Алгоритмы фактически одинаковы, и запросы выполняются в одно и то же время. […]

Это'трудно сказать точную причину[падение производительности при использовании]NOT EXISTS, поскольку это падение является линейным и, по-видимому, не зависит от распределения данных, количества значений в обеих таблицах и т. д., пока оба поля проиндексированы. Поскольку в MySQL есть три фрагмента кода, которые, по сути, выполняют одну работу, возможно, что этот код отвечает заEXISTS делает какую-то дополнительную проверку, которая занимает дополнительное время. […]

MySQL может оптимизировать все три метода, чтобы сделать своего родаNESTED LOOPS ANTI JOIN, [...Однако эти три метода генерируют три разных плана, которые выполняются тремя разными частями кода. Код, который выполняетEXISTS предикат примерно на 30% менее эффективен […]

Тот'почемуЛучший способ поиска пропущенных значений в MySQL - использовать /LEFT JOINIS NULL или жеNOT IN скорее, чем .NOT EXISTS

(выделено)

296

Чтобы использовать IN, у вас должен быть набор, используйте этот синтаксис:

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)
7

К сожалению, похоже, проблема с использованием MySql "НЕ В" на приведенном ниже снимке экрана показана опция подзапроса, возвращающая неверные результаты:

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 
159

Опция подзапроса уже получена, но обратите внимание, что во многих случаяхLEFT JOIN может быть более быстрый способ сделать это:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

Если вы хотите проверить несколько таблиц, чтобы убедиться, чтоне присутствует ни в одной из таблиц (как в SRKR 'комментарий), вы можете использовать это:

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

RelatedQuestions