Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL “NOT IN” consulta 3 tabelas


Evite NOT IN como a praga se
SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1

poderia conter NULL. Em vez disso, use NOT EXISTS ou Left Joins

use junções explícitas, não junções de estilo de 1980 usando o WHERE cláusula

Para ilustrar a miséria de NOT IN:


SQL NOT IN () perigo
create table mStatus
(   id int auto_increment primary key,
    status varchar(10) not null
);
insert mStatus (status) values ('single'),('married'),('divorced'),('widow');

create table people
(   id int auto_increment primary key,
    fullName varchar(100) not null,
    status varchar(10)  null
);

Bloco1:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single');
select * from mstatus where `status` not in (select status from people);

** 3 linhas, como esperado **

Chunk2:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single'),('Kim Billings',null);
select * from mstatus where status not in (select status from people);

sem linhas, hein?

Obviamente isso é 'incorreto'. Ela surge do uso da lógica de três valores pelo SQL, impulsionada pela existência de NULL, um não valor que indica informações ausentes (ou DESCONHECidas). Com NOT IN, Chunk2 é traduzido assim:
status NOT IN ('married', 'divorced', 'widowed', NULL)

Isso é equivalente a:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)

A expressão "status=NULL" é avaliada como UNKNOWN e, de acordo com as regras da lógica de três valores, NOT UNKNOWN também é avaliada como UNKNOWN. Como resultado, todas as linhas são filtradas e a consulta retorna um conjunto vazio.

As soluções possíveis incluem:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null

ou use not exists