Du kan inte referera till ett alias förutom i ORDER BY eftersom SELECT är den näst sista satsen som utvärderas. Två lösningar:
SELECT BalanceDue FROM (
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
) AS x
WHERE BalanceDue > 0;
Eller bara upprepa uttrycket:
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE (InvoiceTotal - PaymentTotal - CreditTotal) > 0;
Jag föredrar det senare. Om uttrycket är extremt komplext (eller dyrt att beräkna) bör du förmodligen överväga en beräknad kolumn (och kanske bevarad) istället, speciellt om många frågor hänvisar till samma uttryck.
PS dina farhågor verkar ogrundade. Åtminstone i detta enkla exempel är SQL Server smart nog att bara utföra beräkningen en gång, även om du har refererat till den två gånger. Gå vidare och jämför planerna; du kommer att se att de är identiska. Om du har ett mer komplext fall där du ser uttrycket utvärderat flera gånger, vänligen posta den mer komplexa frågan och planerna.
Här är 5 exempelfrågor som alla ger exakt samma exekveringsplan:
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;
Resulterande plan för alla fem frågorna: