No puede hacer referencia a un alias excepto en ORDER BY porque SELECT es la penúltima cláusula que se evalúa. Dos soluciones:
SELECT BalanceDue FROM (
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
) AS x
WHERE BalanceDue > 0;
O simplemente repite la expresión:
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE (InvoiceTotal - PaymentTotal - CreditTotal) > 0;
Prefiero este último. Si la expresión es extremadamente compleja (o costosa de calcular), probablemente debería considerar una columna calculada (y tal vez persistente), especialmente si muchas consultas se refieren a esta misma expresión.
PD:tus temores parecen infundados. Al menos en este ejemplo simple, SQL Server es lo suficientemente inteligente como para realizar el cálculo solo una vez, aunque haya hecho referencia a él dos veces. Continúe y compare los planes; Verás que son idénticos. Si tiene un caso más complejo en el que ve la expresión evaluada varias veces, publique la consulta más compleja y los planes.
Aquí hay 5 consultas de ejemplo que arrojan exactamente el mismo plan de ejecución:
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;
Plan resultante para las cinco consultas: