Unikaj NOT IN
jak zaraza, jeśli
SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1
może kiedykolwiek zawierać NULL. Zamiast tego użyj opcji NOT EXISTS lub Left Joins
używaj jawnych złączeń, a nie złączeń w stylu lat 80., używając WHERE
klauzula
Aby zilustrować niedolę NOT IN:
SQL NOT IN () niebezpieczeństwo
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
);
Fragment 1:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single');
select * from mstatus where `status` not in (select status from people);
** 3 rzędy, zgodnie z oczekiwaniami **
Kawałek2:
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);
brak wierszy, co?
Oczywiście jest to „niepoprawne”. Wynika to z użycia przez SQL trójwartościowej logiki, napędzanej istnieniem NULL, nie będącej wartością wskazującą na brakujące (lub NIEZNANE) informacje. Z NOT IN, Chunk2 jest tłumaczony w ten sposób:
status NOT IN ('married', 'divorced', 'widowed', NULL)
Odpowiada to:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)
Wyrażenie „status=NULL” oceniane jest jako NIEZNANE i, zgodnie z regułami logiki trójwartościowej, NIEZNANE również obliczane jest jako NIEZNANE. W rezultacie wszystkie wiersze są odfiltrowywane, a zapytanie zwraca pusty zestaw.
Możliwe rozwiązania to:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null
lub użyj not exists