2012-06-25 7 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)에서 대답은 실제로는 아닐 것입니다. 실제로는 아니요, 계산서 ()를 두 번 썼습니다. 아무도 그 중 어느 것도 만족스럽지 않습니다.

답변

168

SELECT는 평가되는 두 번째 마지막 절이므로 ORDER BY를 제외한 별칭을 참조 할 수 없습니다. 두 가지 해결 방법 :

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

나는 후자를 선호 :

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

또는 단지는 표현을 반복합니다. 표현식이 극도로 복잡하거나 비용이 많이 드는 경우 계산 된 열을 고려해야합니다 (특히 지속성이 높은 경우). 특히 많은 쿼리에서이 동일한 표현식을 참조하는 경우가 있습니다.

추신 : 두려움은 근거없는 것 같습니다. 이 간단한 예제에서는 적어도 두 번 참조 했더라도 SQL Server는 계산을 한 번만 수행 할만큼 똑똑합니다. 계획을 비교하고 비교하십시오. 당신은 그들이 동일하다는 것을 볼 수 있습니다. 표현식이 여러 번 평가되는 복잡한 사례가있는 경우보다 복잡한 쿼리와 계획을 게시하십시오. 다섯 개 쿼리에 대한

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

를 사용하여 여기에

5 예 모두가 동일한 실행 계획을 얻을 수 있음을 조회하다

SELECT c.BalanceDue AS BalanceDue 
FROM Invoices 
cross join (select (InvoiceTotal - PaymentTotal - CreditTotal) as BalanceDue) as c 
WHERE c.BalanceDue > 0;