it-swarm.com.de

Warum tritt bei dieser Abfrage, bei der eine FROM-Klausel fehlt, kein Fehler auf?

Wir haben also eine Abfrage mit einer Unterabfrage, die einen Tippfehler enthält. Es fehlt die FROM-Klausel. Aber wenn Sie es ausführen, tritt kein Fehler auf! Warum!?


SELECT

    1
   ,r.id
   ,'0D4133BE-C1B5-4141-AFAD-B171A2CCCE56'
   ,GETDATE()
   ,1
   ,'Y'
   ,'N'
   ,oldItem.can_view
   ,oldItem.can_update

FROM Role r

JOIN RoleObject oldReport
    ON r.customer_id = oldReport.customer_id

JOIN RoleItem oldItem
    ON oldReport.id = oldItem.role_object_id
        AND r.id = oldItem.role_id

WHERE r.id NOT IN (SELECT
        role_id
    WHERE role_object_id = '0D4133BE-C1B5-4141-AFAD-B171A2CCCE56')

AND oldReport.id = '169BA22F-1614-4EBA-AF45-18E333C54C6C'
9
Wjdavis5

Diese Aussage ist legal (mit anderen Worten, es ist kein FROM erforderlich):

SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;

Der Trick ist, wenn Sie einen Spaltennamen einführen, der eindeutig nicht existieren kann. Also scheitern diese:

SELECT name WHERE 1 = 1;

SELECT x = 1 WHERE id > 0;

Nachricht 207, Ebene 16, Zustand 1
Ungültiger Spaltenname 'Name'.
Nachricht 207, Ebene 16, Zustand 1
Ungültiger Spaltenname 'id'.

Wenn die ungültige Spalte jedoch in eine Unterabfrage eingefügt wird, wird SQL Server, wenn es diese Spalte im inneren Bereich der Unterabfrage nicht findet, zu einem äußeren Bereich durchlaufen und die Unterabfrage mit diesem äußeren Bereich korrelieren lassen. Dies gibt alle Zeilen zurück, zum Beispiel:

SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);

Weil es im Wesentlichen heißt:

SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
              ^^^^^^^^^^^                       -----------
                   |                                 |
                   -----------------------------------    */

Sie benötigen nicht einmal eine WHERE -Klausel in der Unterabfrage:

SELECT * FROM sys.columns WHERE name IN (SELECT name);

Sie können sehen, dass es wirklich auf den äußeren Bereichstisch schaut, weil dies:

SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');

Gibt weit weniger Zeilen zurück (11 auf meinem System).

Dies beinhaltet die Einhaltung des Standards für das Scoping. Sie können ähnliche Dinge sehen, wenn Sie zwei # temp-Tabellen haben:

CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);

SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);

Offensichtlich sollte dies ein Fehler sein, richtig, da es in #bar Kein foo gibt? Nee. Was passiert ist, dass SQL Server sagt: "Oh, ich habe hier kein foo gefunden, Sie müssen das andere gemeint haben."

Außerdem würde ich im Allgemeinen NOT IN Vermeiden. NOT EXISTS Kann in einigen Szenarien effizienter sein, aber was noch wichtiger ist, sein Verhalten ändert sich nicht, wenn es möglich ist, dass die Zielspalte NULL lautet. Siehe diesen Beitrag für weitere Informationen .

21
Aaron Bertrand

Ich habe dies 2016 mit einem vereinfachten Beispiel reproduziert:

declare @t1 table (c1 int, c2 int, c3 int)
insert into @t1 values (1,2,3), (2,3,4), (3,4,5)

select * from @t1
where
    c1 not in 
    (select c2 where c3 = 3)

Es scheint, dass c2 und c3 für jede Zeile ausgewertet werden.

2
paulbarbin

In SQL Server erfordert die SELECT-Syntax keinen FROM-Abschnitt. Wenn Sie FROM weglassen, verwendet die select-Anweisung eine "Dummy" -Tabelle mit einer Zeile und keinen Spalten. Damit

select 'x' as c where ...

gibt eine Zeile zurück, wenn der Ausdruck wahr ist, und keine Zeilen, wenn er falsch ist.

1
Piotr