Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête MySQL "NOT IN" 3 tables

Évitez NOT IN comme la peste si

SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1

pourrait jamais contenir NULL. Utilisez plutôt NOT EXISTS ou Left Joins

utilisez des jointures explicites, et non des jointures de style années 1980 en utilisant WHERE clause

Pour illustrer la misère de NOT IN :

Danger SQL NOT IN ()

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
);

Bloc1 :

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

** 3 rangées, comme prévu **

Morceau2 :

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);

pas de rangées, hein ?

Évidemment, c'est "incorrect". Il découle de l'utilisation par SQL d'une logique à trois valeurs, pilotée par l'existence de NULL, une non-valeur indiquant des informations manquantes (ou INCONNUES). Avec NOT IN, Chunk2, il est traduit comme ceci :

status NOT IN ('married', 'divorced', 'widowed', NULL)

Cela équivaut à :

NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)

L'expression "status=NULL" est évaluée à UNKNOWN et, selon les règles de la logique à trois valeurs, NOT UNKNOWN est également évaluée à UNKNOWN. Par conséquent, toutes les lignes sont filtrées et la requête renvoie un ensemble vide.

Les solutions possibles incluent :

select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null

ou utilisez not exists