MySQL: NOT IN с sub select не работи според очакванията?

Това е моето запитване:

SELECT customer_email 
FROM   sales_flat_order 
WHERE  customer_email NOT IN (SELECT customer_email
                              FROM   sales_flat_order
                              WHERE  status != 'holded');

Има 3 реда със състояние holded за моя тест customer_email [email protected], няма друг статус за този имейл. По някаква причина пълната заявка не връща съвпадения. Когато попълня NOT IN ръчно по този начин, работи, получавам своите 3 реда:

SELECT customer_email 
FROM   sales_flat_order 
WHERE  customer_email NOT IN ('whatever', 'foobar', '[email protected]');

И така, какво правя грешно тук?

Fiddle: https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=f990a09528d872d53ec

Цигулката обаче работи според очакванията, моята таблица е много по-голяма, но колоните са от същия тип.

Благодаря!


person Arnie    schedule 26.11.2019    source източник
comment
Тук трябва да предоставите примерни данни.   -  person Tim Biegeleisen    schedule 26.11.2019
comment
Fiddle е предоставен в публикацията ми, сор.   -  person Arnie    schedule 26.11.2019


Отговори (1)


Ще направя предположението, че има поне един запис в sales_flat_order, който отговаря на условие status != 'holded' и чието customer_email е NULL.

(NOT) IN е известен с NULLs, ето един пример.

Разгледайте следното запитване:

SELECT 1 WHERE 1 NOT IN (SELECT 2 UNION ALL SELECT 3)

Това дава запис със стойност 1, както се очаква.

Ако обаче промените това на:

SELECT 1 WHERE 1 NOT IN (SELECT 2 UNION ALL SELECT NULL)

След това заявката създава празен набор от резултати. Това е добре известен проблем с (NOT) IN. Поради тази причина обикновено трябва да избягвате този синтаксис и да използвате (NOT) EXISTS вместо него. Горната заявка може да бъде пренаписана като:

SELECT 1 a
FROM (SELECT 1 a) t1
WHERE NOT EXISTS (
    SELECT 1
    FROM (SELECT 2 a UNION ALL SELECT NULL) t2
    WHERE t1.a = t2.a
)

Демо на DB Fiddle

За вашето запитване:

SELECT customer_email 
FROM sales_flat_order s
WHERE NOT EXISTS (
    SELECT 1
    FROM sales_flat_order s1
    WHERE s1.customer_email = s.customer_email AND s.status != 'holded'
);
person GMB    schedule 26.11.2019
comment
Благодаря, прав си, в БД има NULL! Тази заявка значително по-бавна ли е? - person Arnie; 26.11.2019
comment
@Арни: не, не очаквам това да е по-бавно от текущата ви заявка. За ефективност искате индекс на sales_flat_order(customer_email, status ) - person GMB; 26.11.2019