2008-11-17 9 views
30

Ich bin sicher, einen dummen Fehler zu machen, aber ich kann nicht verstehen, was:SQL-Abfrage Frage: SELECT ... NICHT IN

In SQL Server 2005 Ich versuche, wählen Sie alle Kunden mit Ausnahme derjenigen, die eine Reservierung vorgenommen haben vor 2 UHR MORGENS.

Wenn ich diese Abfrage ausführen:

SELECT idCustomer FROM reservations 
WHERE idCustomer NOT IN 
    (SELECT distinct idCustomer FROM reservations 
    WHERE DATEPART (hour, insertDate) < 2) 

ich 0 Ergebnisse.

Aber

SELECT idCustomer FROM reservations 

kehrt 152.000 Ergebnisse und die "NOT IN" Teil:

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 

kehrt nur 284 Zeilen

+0

Warum würden Sie ein Distinct setzen in dir NICHT IN? Ist die 5 in (1, 1, 2, 2, 3, 4, 4, 4, 4, 4)? Es ist egal, ob es Duplikate gibt. –

+1

Sicher, ich wurde ein wenig verzweifelt und versuchte alles :) –

Antwort

53
SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 
    and idCustomer is not null 

Stellen Sie sicher, Ihre Liste Parameter nicht null enthält Werte.

Hier ist eine Erklärung:

WHERE field1 NOT IN (1, 2, 3, null) 

ist die gleiche wie:

WHERE NOT (field1 = 1 OR field1 = 2 OR field1 = 3 OR field1 = null) 
  • Das letzte Vergleich auf Null auswertet.
  • Diese Null wird mit dem Rest des booleschen Ausdrucks OR-verknüpft und ergibt null. (*)
  • null ist negiert und ergibt null.
  • null ist nicht wahr - die where-Klausel enthält nur echte Zeilen, daher werden alle Zeilen gefiltert.

(*) Edit: Diese Erklärung ist ziemlich gut, aber ich möchte eine Sache beziehen sich auf zukünftige Spitzfindigkeiten abwehren. (WAHR ODER NULL) würde zu WAHR ausgewertet. Dies ist relevant, wenn z. B. field1 = 3 ist. Dieser TRUE-Wert würde auf FALSE negiert und die Zeile würde gefiltert.

+0

Das war es, danke! Ich verstehe immer noch nicht warum. Nicht-Null-Werte sollten nicht durch die Null-Werte gefiltert werden, oder? –

+0

Tolle Erklärung David, vielen Dank! –

2

es ist SQL 2005 gegeben, können Sie auch versuchen, dieses Es ist ähnlich wie Oracle MINUS-Befehl (Gegenteil von UNION)

Aber ich würde auch vorschlagen, die DATEPART (Stunde, Insert) Zugabe Spalte für Debug

SELECT idCustomer FROM reservations 
EXCEPT 
SELECT idCustomer FROM reservations WHERE DATEPART (hour, insertDate) < 2 
0
SELECT Reservations.idCustomer FROM Reservations (nolock) 
LEFT OUTER JOIN @reservations ExcludedReservations (nolock) ON Reservations.idCustomer=ExcludedReservations.idCustomer AND DATEPART(hour, ExcludedReservations.insertDate) < 2 
WHERE ExcludedReservations.idCustomer IS NULL AND Reservations.idCustomer IS NOT NULL 
GROUP BY Reservations.idCustomer 

[Update: weitere Kriterien hinzugefügt idCustomer ist NULL zu handhaben, die das ursprüngliche Plakat hatte offenbar das Hauptproblem war]

+0

Hallo Kevin, das Problem war, dass customerId Nullable war und als @David wies aber trotzdem vielen Dank! –

+0

Ok. Hinzugefügt in den zusätzlichen Kriterien nur für die Vollständigkeit: -P Ich habe nicht die Daten, um es auszuprobieren, aber ich wäre gespannt, den Unterschied in Ausführung Pläne von NOT IN gegenüber dem OUTER JOIN zu sehen. Wie auch immer, froh, dass Ihr Problem gelöst ist. –

0

Tut mir leid, wenn ich den Punkt verpasst habe, aber würde das Folgende nicht tun, was du willst?

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART(hour, insertDate) >= 2 
+0

Ich dachte das gleiche ... Aber wenn ein Kunde zwei Reservierungen hat, eine vor 2Am und eine danach, werden Sie ihn einschließen, und sein würde nicht. –

+0

Ah, das macht Sinn, mein Gehirn feuert heute nicht auf allen Zylindern! –

6

Es ist immer gefährlich NULL in der IN Liste zu haben - es verhält sich oft wie für die IN erwartet, aber nicht für die NOT IN:

IF 1 NOT IN (1, 2, 3, NULL) PRINT '1 NOT IN (1, 2, 3, NULL)' 
IF 1 NOT IN (2, 3, NULL) PRINT '1 NOT IN (2, 3, NULL)' 
IF 1 NOT IN (2, 3) PRINT '1 NOT IN (2, 3)' -- Prints 
IF 1 IN (1, 2, 3, NULL) PRINT '1 IN (1, 2, 3, NULL)' -- Prints 
IF 1 IN (2, 3, NULL) PRINT '1 IN (2, 3, NULL)' 
IF 1 IN (2, 3) PRINT '1 IN (2, 3)' 
+0

Guter Punkt. Ich habe jedoch nie einen Fall gefunden, bei dem die Verwendung von null in der In-Liste eine korrektere Antwort lieferte. –

+0

Genau - das Problem ist, wenn die Liste dynamisch ist und Sie nicht wissen, dass der NULL da ist und Sie ein IN nehmen und es in ein NOT IN ändern. –

-1
SELECT MIN(A.maxsal) secondhigh 
FROM (
     SELECT TOP 2 MAX(EmployeeBasic) maxsal 
     FROM M_Salary 
     GROUP BY EmployeeBasic 
     ORDER BY EmployeeBasic DESC 
    ) A 
+3

Willkommen bei SO. Vielleicht möchten Sie diese http://stackoverflow.com/help/how-to-answer lesen, wie Sie gute Antworten verfassen können. Nur Code-Antworten sind nicht sehr hilfreich. Sie können eine kurze Beschreibung hinzufügen, wie das Problem gelöst wird. – thebenman

-1
select * from table_name where id=5 and column_name not in ('sandy,'pandy'); 
+1

Willkommen bei SO. Vielleicht möchten Sie diese stackoverflow.com/help/how-to-answer lesen, wie Sie gute Antworten verfassen. Nur Code-Antworten sind nicht sehr hilfreich. Sie können eine kurze Beschreibung hinzufügen, wie das Problem gelöst wird – GhostCat