Vermeiden Sie NOT IN
wie die Pest, wenn
SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1
könnte jemals NULL enthalten. Verwenden Sie stattdessen NOT EXISTS oder Left Joins
Verwenden Sie explizite Joins, keine Joins im Stil der 1980er Jahre mit WHERE
Klausel
Um das Elend von NOT IN zu veranschaulichen:
SQL NICHT IN () Gefahr
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 Zeilen, wie erwartet **
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);
keine Reihen, huh?
Offensichtlich ist dies "falsch". Es ergibt sich aus der Verwendung von dreiwertiger Logik in SQL, angetrieben durch die Existenz von NULL, einem Nichtwert, der fehlende (oder UNBEKANNTE) Informationen anzeigt. Mit NOT IN, Chunk2 wird es wie folgt übersetzt:
status NOT IN ('married', 'divorced', 'widowed', NULL)
Dies entspricht:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)
Der Ausdruck "status=NULL" wird zu UNKNOWN ausgewertet und nach den Regeln der dreiwertigen Logik wird NOT UNKNOWN ebenfalls zu UNKNOWN ausgewertet. Als Ergebnis werden alle Zeilen herausgefiltert und die Abfrage gibt eine leere Menge zurück.
Mögliche Lösungen sind:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null
oder verwenden Sie not exists