WHERE子句中的引用别名(在SELECT中计算)


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

在WHERE子句中不能使用在选定列的列表中设置为变量的计算值“ BalanceDue”。

有办法吗?在这个相关的问题(在Where子句中的MySQL Select Statment中使用变量)中,答案似乎是,实际上,不,您只需两次写出计算(在查询中执行该计算),就没有这是令人满意的。

Answers:


237

除了ORDER BY外,您不能引用别名,因为SELECT是第二个被评估的子句。两种解决方法:

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,您的担心似乎没有根据。至少在这个简单的示例中,SQL Server足够聪明,只需要执行一次计算,即使您已经两次引用了它。继续比较计划;您会看到它们是相同的。如果您遇到的情况更为复杂,则该表达式会被多次评估,请发布更复杂的查询和计划。

以下是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;

所有五个查询的结果计划:

在此处输入图片说明


11
哇。SQL Server足够聪明,只执行一次计算即可
Alternativefaraz

5
哇,这是一个非常高质量的答案!
悉达多

我在MERGE语句中需要一些额外的条件,这是我可以使其起作用的唯一方法。谢谢!
埃里克·伯多

1
@EricBurdo如果您正在使用MERGE,请确保已将所有这些考虑在内:MERGE谨慎
亚伦·贝特朗

11

您可以使用 cross apply

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

4

实际上,可以有效地定义一个可以在SELECT,WHERE和其他子句中使用的变量。

交叉联接不一定允许对引用的表列进行适当的绑定,但是OUTER APPLY允许-并且更透明地处理null。

SELECT
    vars.BalanceDue
FROM
    Entity e
OUTER APPLY (
    SELECT
        -- variables   
        BalanceDue = e.EntityTypeId,
        Variable2 = ...some..long..complex..expression..etc...
    ) vars
WHERE
    vars.BalanceDue > 0

Syed Mehroz Alam的荣誉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.