2012-06-25 23 views
88
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue 
FROM Invoices 
WHERE BalanceDue > 0 --error 

WHERE句では、選択した列のリストの変数として設定された計算値 'BalanceDue'を使用できません。WHERE句の別名参照(SELECTで計算)

方法はありますか?この関連する質問(Using a variable in MySQL Select Statment in a Where Clause)では、実際には答えが返ってくるように思えますが、計算では()、その計算を2回実行しても問題はありません。

答えて

168

SELECTは評価される最後の句であるため、ORDER BY以外の別名は参照できません。 2つの回避策:

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

それとも表現を繰り返す:私は後者を好む

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

を。式が非常に複雑な場合(または計算にコストがかかる場合)、特に多くのクエリがこの同じ式を参照する場合は、おそらく計算列を考慮する必要があります(おそらく永続化する)。

PSあなたの恐怖は根拠がありません。この単純な例では、少なくとも2回参照したとしても、SQL Serverは計算を1回だけ実行するほどスマートです。進んで計画を比較してください。それらが同一であることがわかります。式が複数回評価されるより複雑なケースがある場合は、より複雑なクエリとプランを投稿してください。ここで

5の例では、すべてが正確に同じ実行計画を生成することを照会します:

すべての5つのクエリの計画結果の
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; 

enter image description here

+0

ありがとうAaron! –

+7

うわー。 SQL Serverは一度だけ計算を実行するほどスマートです – alternatefaraz

+3

これは非常に高品質な答えです。 – Siddhartha

0

をあなたはcross join

を使用してこれを行うことができます
SELECT c.BalanceDue AS BalanceDue 
FROM Invoices 
cross join (select (InvoiceTotal - PaymentTotal - CreditTotal) as BalanceDue) as c 
WHERE c.BalanceDue > 0; 
関連する問題