Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Alias ​​di riferimento (calcolato in SELECT) nella clausola WHERE

Non puoi fare riferimento a un alias se non in ORDER BY perché SELECT è la penultima clausola valutata. Due soluzioni alternative:

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

Oppure ripeti semplicemente l'espressione:

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

preferisco quest'ultimo Se l'espressione è estremamente complessa (o costosa da calcolare) dovresti probabilmente considerare una colonna calcolata (e forse persistente), soprattutto se molte query fanno riferimento a questa stessa espressione.

PS le tue paure sembrano infondate. Almeno in questo semplice esempio, SQL Server è abbastanza intelligente da eseguire il calcolo solo una volta, anche se è stato fatto riferimento due volte. Vai avanti e confronta i piani; vedrai che sono identici Se hai un caso più complesso in cui vedi l'espressione valutata più volte, pubblica la query più complessa e i piani.

Ecco 5 query di esempio che producono tutte lo stesso identico piano di esecuzione:

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;

Piano risultante per tutte e cinque le query: