Vermijd NOT IN
als de pest als
SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1
kan ooit NULL bevatten. Gebruik in plaats daarvan NOT EXISTS of Left Joins
gebruik expliciete joins, geen joins uit de jaren 80-stijl met de WHERE
clausule
Om de ellende van NOT IN te illustreren:
SQL NIET IN () gevaar
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
);
Chunk1:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single');
select * from mstatus where `status` not in (select status from people);
** 3 rijen, zoals verwacht **
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);
geen rijen, hè?
Dit is duidelijk 'onjuist'. Het komt voort uit SQL's gebruik van driewaardige logica, aangedreven door het bestaan van NULL, een niet-waarde die ontbrekende (of ONBEKENDE) informatie aangeeft. Met NOT IN, Chunk2 wordt het als volgt vertaald:
status NOT IN ('married', 'divorced', 'widowed', NULL)
Dit komt overeen met:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)
De uitdrukking "status=NULL" resulteert in UNKNOWN en, volgens de regels van de driewaardige logica, evalueert NOT UNKNOWN ook op UNKNOWN. Als resultaat worden alle rijen uitgefilterd en retourneert de query een lege set.
Mogelijke oplossingen zijn:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null
of gebruik not exists