引用 WHERE 子句中的列别名

Referring to a Column Alias in a WHERE Clause

提问人:user990016 提问时间:12/4/2011 最后编辑:Lukasz Szozdauser990016 更新时间:9/24/2022 访问量:309513

问:

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE daysdiff > 120

我明白了

“无效的列名称 daysdiff”。

Maxlogtm 是一个日期时间字段。正是这些小事让我发疯。

SQL 服务器 T-SQL SQL-SERVER-2005

评论

0赞 Ash Burlaczenko 12/4/2011
不确定MySQL,但也许别名需要用 ticks 包装。`daysdiff`

答:

287赞 Jamie F 12/4/2011 #1
SELECT
   logcount, logUserID, maxlogtm,
   DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE ( DATEDIFF(day, maxlogtm, GETDATE() > 120)

通常,您不能在子句中引用字段别名。(将其视为整个(包括别名)在子句之后应用。WHERESELECTWHERE

但是,正如其他答案中提到的,您可以强制 SQL 处理在子句之前处理。这通常使用括号来强制执行逻辑操作顺序,或者使用通用表表达式 (CTE) 来完成:SELECTWHERE

括号/子选择:

SELECT
   *
FROM
(
   SELECT
      logcount, logUserID, maxlogtm,
      DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary   
) as innerTable
WHERE daysdiff > 120

或者查看 Adam 的答案以获取相同的 CTE 版本。

评论

24赞 david blaine 12/21/2012
这不可能直接实现,因为按时间顺序,WHERE 发生在 SELECT 之前,而 SELECT 始终是执行链中的最后一步。参考 - stackoverflow.com/questions/356675/...
0赞 Răzvan Flavius Panda 5/31/2016
afaik:如果 select 中的别名是相关的子查询,这将起作用,而 CTE 解决方案则不起作用。
0赞 Bakhtiyor 3/26/2019
正如 Pascal stackoverflow.com/a/38822328/282887 在他的回答中提到的,你可以使用 HAVING 子句,它似乎比子查询工作得更快。
0赞 Jamie F 3/26/2019
@Bakhtiyor 答案在大多数 SQL 环境中都不起作用,包括这个问题所涉及的 MS-SQL。(在 T-SQL 中,需要聚合函数。HAVINGHAVING
0赞 Mr. Boy 12/10/2021
我从来不知道你不能引用别名,直到我刚才遇到这个问题。喜欢这种解决方法...这是否会对性能产生重大影响?
97赞 Adam Wenger 12/4/2011 #2

如果要在子句中使用别名,则需要将其包装在子选择或 CTE 中:WHERE

WITH LogDateDiff AS
(
   SELECT logcount, logUserID, maxlogtm
      , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary
)
SELECT logCount, logUserId, maxlogtm, daysdiff
FROM LogDateDiff
WHERE daysdiff > 120

评论

2赞 James 7/4/2014
你碰巧知道这如何公平地提高效率吗?使用 CTE 是否有额外的开销?
5赞 Adam Wenger 7/5/2014
CTE 只是子查询的更漂亮的语法,因此性能与此类似。根据我的经验,对于这样的操作,性能差异并不是我所关心的,但是在您的环境中测试它应该相当简单,以查看您的特定表/查询是否受到此操作的不利影响,而不是在 where 子句中专门调用公式。我怀疑你不会注意到其中的区别。
0赞 symbiont 8/21/2017
CTE 非常好,直到您尝试将其用作子查询。我不得不求助于将它们创建为视图来嵌套它们。我认为这是一个严重的SQL缺点
11赞 Roman Pekar 10/10/2014 #3

如果您不想在 CTE 中列出所有列,另一种方法是使用外部应用

select
    s.logcount, s.logUserID, s.maxlogtm,
    a.daysdiff
from statslogsummary as s
    outer apply (select datediff(day, s.maxlogtm, getdate()) as daysdiff) as a
where a.daysdiff > 120
9赞 Shekhar Joshi 3/31/2015 #4

使用子查询怎么样(这在Mysql中对我有用)?

SELECT * from (SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary) as 'your_alias'
WHERE daysdiff > 120
22赞 Pascal 8/8/2016 #5

在不重复代码的情况下执行此操作的最有效方法是使用 HAVING 而不是 WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120

评论

3赞 tokland 11/25/2016
我认为在别名上使用不是标准的(不过它确实适用于MySQL)。具体来说,我认为它不适用于 SQL Server。HAVING
5赞 Vadzim 11/3/2017
SQL Server:[S0001][207] Invalid column name 'daysdiff'
8赞 Vadzim 11/3/2017
SQL Server:[S0001][8121] Column 'day' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
0赞 dcafdg 10/20/2022
@Vadzim - 我只是收到错误无论哪种方式,它都无法在 SQL Server 中工作...Invalid column name '<name>'.
7赞 roier.rdz 3/19/2017 #6

HAVING 在 MySQL 中工作 根据文档:

HAVING 子句已添加到 SQL 中,因为 WHERE 关键字无法 与聚合函数一起使用。

评论

3赞 baltermia 6/9/2021
不过,问题是关于sql-server
3赞 Tommy 10/21/2021
尽管问题是关于SQL Server的,但这个答案对我们使用mysql非常有帮助,他们通过Google到达了这里!谷歌没有索引问题标签,所以谢谢你的回答!
5赞 Lukasz Szozda 8/26/2018 #7

您可以引用列别名,但您需要使用以下命令来定义它:CROSS/OUTER APPLY

SELECT s.logcount, s.logUserID, s.maxlogtm, c.daysdiff
FROM statslogsummary s
CROSS APPLY (SELECT DATEDIFF(day, s.maxlogtm, GETDATE()) AS daysdiff) c
WHERE c.daysdiff > 120;

DBFiddle 演示

优点:

  • 表达式的单一定义(更易于维护/无需复制粘贴)
  • 无需使用 CTE/outerquery 包装整个查询
  • 可以参考WHERE/GROUP BY/ORDER BY
  • 可能更好的性能(单次执行)

评论

1赞 Martin 10/26/2018
值得一提的是,它仅适用于 SQL Server
2赞 Lukasz Szozda 10/26/2018
@MartinZinovsky 问题被标记为 和 :)sql-servert-sql
1赞 Scy 2/25/2020 #8

来到这里看起来与此类似,但带有 CASE WHEN,并像这样结束使用 where:也许您可以直接使用 in。 像这样:WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0DATEDIFFWHERE

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
2赞 Michael Henry 8/11/2020 #9

对我来说,在 WHERE 子句中使用 ALIAS 的最简单方法是创建一个子查询并从中进行选择。

例:

WITH Q1 AS (
    SELECT LENGTH(name) AS name_length,
    id,
    name
    FROM any_table
)

SELECT id, name, name_length FROM Q1 WHERE name_length > 0
0赞 Roman Samarsky 12/1/2023 #10

使用 HAVING 子句,因为 WHERE 关键字不能与聚合函数一起使用。

SELECT
    logcount,
    logUserID,
    maxlogtm,
    DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120