Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Referenzalias (berechnet in SELECT) in WHERE-Klausel

Sie können nur in ORDER BY auf einen Alias ​​verweisen, da SELECT die vorletzte Klausel ist, die ausgewertet wird. Zwei Problemumgehungen:

SELECT BalanceDue FROM (
  SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
  FROM Invoices
) AS x
WHERE BalanceDue > 0;

Oder wiederholen Sie einfach den Ausdruck:

SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE  (InvoiceTotal - PaymentTotal - CreditTotal)  > 0;

Ich bevorzuge letzteres. Wenn der Ausdruck extrem komplex (oder kostspielig zu berechnen) ist, sollten Sie stattdessen wahrscheinlich eine berechnete Spalte in Betracht ziehen (und vielleicht beibehalten), insbesondere wenn sich viele Abfragen auf denselben Ausdruck beziehen.

PS Deine Befürchtungen scheinen unbegründet. Zumindest in diesem einfachen Beispiel ist SQL Server intelligent genug, um die Berechnung nur einmal durchzuführen, obwohl Sie zweimal darauf verwiesen haben. Gehen Sie voran und vergleichen Sie die Pläne; Sie werden sehen, dass sie identisch sind. Wenn Sie einen komplexeren Fall haben, in dem der Ausdruck mehrmals ausgewertet wird, posten Sie bitte die komplexere Abfrage und die Pläne.

Hier sind 5 Beispielabfragen, die alle denselben Ausführungsplan ergeben:

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE LEN(name) + column_id > 30;

SELECT x FROM (
SELECT LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE column_id + LEN(name) > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE LEN(name) + column_id > 30;

Resultierender Plan für alle fünf Abfragen: