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

Nic*_*sen 119 sql t-sql sql-server

SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE BalanceDue > 0 --error
Run Code Online (Sandbox Code Playgroud)

在WHERE子句中不能使用在所选列列表中设置为变量的计算值"BalanceDue".

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

Aar*_*and 221

除了ORDER BY之外,您不能引用别名,因为SELECT是已计算的第二个最后一个子句.两个解决方法:

SELECT BalanceDue FROM (
  SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
  FROM Invoices
) AS x
WHERE BalanceDue > 0;
Run Code Online (Sandbox Code Playgroud)

或者只是重复表达式:

SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE  (InvoiceTotal - PaymentTotal - CreditTotal)  > 0;
Run Code Online (Sandbox Code Playgroud)

我更喜欢后者.如果表达式非常复杂(或计算代价很高),您应该考虑使用计算列(并且可能是持久化的),尤其是在很多查询引用相同表达式的情况下.

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;
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

  • 哇.SQL Server非常智能,只能执行一次计算 (8认同)
  • 哇这是一个非常高质量的答案! (4认同)

Man*_*noj 6

你可以使用 cross apply

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