2011-07-29 6 views
6

Wydaje się to takie proste, jestem oszołomiony z powodu braku lepszego słowa. Mam dwie tabele, nazwijmy je albums i artistsNull i IN() dostarczają nieoczekiwanych wyników.

CREATE TABLE `albums` (
    `album_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `artist_id` bigint(20) DEFAULT NULL, 
    `name` varchar(200) NOT NULL, 
    PRIMARY KEY (`album_id`) 
) 
CREATE TABLE `artists` (
    `artist_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `name` varchar(250) NOT NULL, 
    PRIMARY KEY (`artist_id`) 
) 

Istnieje kilkaset tysięcy reconds w każdej tabeli. Niektóre wiersze albumów mają wartość zerową artist_id, to jest oczekiwane.

Jednak, kiedy należy wykonać następujące zapytanie znaleźć artystów bez albumach:

SELECT * FROM artists WHERE artist_id NOT IN (SELECT artist_id FROM albums)

... kwerenda zwraca zero wyników. Wiem, że to nie jest prawda. Spróbowałem więc ten jeden:

SELECT * FROM artists WHERE artist_id NOT IN (SELECT artist_id FROM albums WHERE artist_id IS NOT NULL)

... i wrócić kilka tysięcy wierszy. Moje pytanie brzmi: dlaczego pierwsze zapytanie zdało się działać na idei, że jakakolwiek liczba = NULL? Czy jest to dziwny efekt, który NULL ma na oświadczeniu IN()? Czuję, że jest to coś podstawowego, czego mi brakowało. Zazwyczaj nie używam NULL w moich tabelach db.

Odpowiedz

7

Dlatego NOT EXISTS jest semantycznie poprawne

SELECT * FROM artists ar 
WHERE NOT EXISTS 
    (SELECT * FROM albums al WHERE ar.artist_id = al.artist_id) 

logicznych:

  • NOT IN (x, y, NULL) jest rzeczywiście
    • NOT (x OR y OR NULL) jest rzeczywiście
      • (NOT x) AND (NOT y) AND (NOT NULL)

Więc NULL unieważnia cały NOT IN

+0

Wygląda na to, że NOT EXISTS również było marginalnie szybsze. Dziękuję bardzo za informacje! –

7

Szybka odpowiedź - instrukcja IN jest skrótem do =a OR =b OR .... Jeśli uwzględnisz wartości null na tej liście, myślę, że to łamie to oświadczenie. Twoja druga opcja to prawdopodobnie lepsza opcja.

Lub użycie sprzężenia może również działać i być bardziej wydajne.

+0

true LUB unknown jest wartością true.I to NIE JEST: który zepsuje się inaczej – gbn

2

Ma to związek ze sposobem SQL NULL użytkownika są interpretowane - Trzeba myśleć o nich jako wartość nieznany.

Powiedzmy, że masz artist_id = 1

Po uruchomieniu następuje:

artist_id = NULL 

Zamiast coraz 'false' - pojawi się 'nieznany';

Po uruchomieniu zapytania takiego jak twoje zwracane są tylko wartości mające wartość "PRAWDA".

artist_id IN (NULL, NULL, NULL...) = UNKNOWN 
artist_id NOT IN (NULL, NULL, NULL....) = UNKNOWN 
+0

Wystarczająco uczciwe, choć chciałbym wtedy odpowiedzieć - dlaczego w ogóle użyć null? Gdyby to był mój projekt bazy danych, użyłbym 0 w miejsce wartości null, gdy nie ma artysty. Czy jest jakiś ważny powód, dla którego należy użyć wartości null? –

+0

To zdecydowanie dyskusyjne. Osobiście używam ich jako wygodnych symboli zastępczych - jeśli ładuję tabelę, która często ma wiele nieznanych pól, zamiast zawsze ustawiać puste wartości (tj. ", N/a, itp.), Po prostu konsekwentnie trzymam NULL. Jestem zadowolony z tej metody - choć niektórzy uznają tę złą praktykę. – chris

+2

@Chris, niektórzy twierdzą, że używanie wartości zastępczych jest bardziej mylące, ponieważ każdy oglądający dane musi wiedzieć, która wartość jest symbolem zastępczym. Nie może to być rozwiązanie uniwersalne, ponieważ zawsze będą projekty, w których nie można wybrać rozsądnej wartości zastępczej. Istnieją także praktyczne zalety korzystania z NULL - wymaga to mniej pamięci zarówno w tabelach jak i indeksach, a zatem może również zwiększyć wydajność. –

Powiązane problemy