Vous ne pouvez pas référencer un alias sauf dans ORDER BY car SELECT est l'avant-dernière clause évaluée. Deux solutions de contournement:
SELECT BalanceDue FROM (
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
) AS x
WHERE BalanceDue > 0;
Ou répétez simplement l'expression:
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE (InvoiceTotal - PaymentTotal - CreditTotal) > 0;
Je préfère ce dernier. Si l'expression est extrêmement complexe (ou coûteuse à calculer), vous devriez probablement envisager une colonne calculée (et peut-être persistante) à la place, surtout si de nombreuses requêtes font référence à cette même expression.
PS vos craintes ne semblent pas fondées. Dans cet exemple simple au moins, SQL Server est suffisamment intelligent pour n'effectuer le calcul qu'une seule fois, même si vous l'avez référencé deux fois. Allez-y et comparez les plans; vous verrez qu'ils sont identiques. Si vous avez un cas plus complexe où vous voyez l'expression évaluée plusieurs fois, veuillez publier la requête la plus complexe et les plans.
Voici 5 exemples de requêtes qui donnent toutes exactement le même plan d'exécution:
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 résultant pour les cinq requêtes: