在WHERE子句中引用列别名


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

我懂了

“无效的列名daysdiff”。

Maxlogtm是日期时间字段。是让我发疯的小东西。


对于mysql不确定,但是别名需要用ticks包装`daysdiff`
Ash Burlaczenko

Answers:


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

通常,您不能在WHERE子句中引用字段别名。(将其视为SELECT包括别名在内的全部内容,在该WHERE子句之后应用。)

但是,如其他答案所述,您可以强制将SQL视为SELECTWHERE子句之前进行处理。通常使用圆括号来强制操作的逻辑顺序,或者使用通用表表达式(CTE):

括号/子选择:

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

或参阅亚当的CTE版本答案。


16
这不可能直接实现,因为按时间顺序,WHERE发生在SELECT之前,这始终是执行链中的最后一步。REFER - stackoverflow.com/questions/356675/...
大卫·布莱恩

afaik如果选择中的别名是相关子查询,则它将起作用,而CTE解决方案则无效。
拉兹万·弗拉维斯·熊猫

如Pascal在他的此处stackoverflow.com/a/38822328/282887的回答中所述,您可以使用HAVING子句,该子句的工作速度似乎比子查询快。
巴赫蒂奥尔

@Bakhtiyor HAVING答案不适用于大多数SQL环境,包括此问题所涉及的MS-SQL。(在T-SQL中,HAVING需要聚合函数。)
Jamie F

72

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

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
您是否知道这种公平的交易效率如何?使用CTE是否会有额外的开销?
詹姆斯

5
CTE只是子查询的更漂亮语法,因此性能将与此类似。根据我的经验,性能差异并不是让我担心的事情,但是在您的环境中对其进行测试应该相当简单,以查看特定的表/查询是否受到此行为的不利影响。公式专门在where子句中。我怀疑您不会注意到有什么不同。
亚当·温格

在您尝试将其中一个用作子查询之前,CTE非常好。我不得不诉诸于创建它们作为嵌套它们的视图。我认为这是一个严重的SQL缺点
symbiont

10

无需重复执行代码的最有效方法是使用HAVING而不是WHERE

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

1
我认为HAVING在别名上使用不是标准的(尽管它确实适用于MySQL)。具体来说,我认为它不适用于SQL Server。
tokland

2
SQL Server:[S0001][207] Invalid column name 'daysdiff'
Vadzim

3
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.
Vadzim

9

如果您不想在CTE中列出所有列,则另一种方法是使用outer apply

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

6

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

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

4

根据文档,HAVING可在MySQL中工作:

HAVING子句被添加到SQL,因为关键字无法与合计函数使用的地方。


4

您可以引用列别名,但是您需要使用定义它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
值得一提的是,它仅适用于SQL Server
Martin Zinovsky,

1
@MartinZinovsky问题标记为sql-servert-sql:)
Lukasz Szozda 18-10-26

0

来到这里看起来类似,但是带有CASE WHEN,并最终使用了这样的位置:WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0也许您可以直接DATEDIFF在其中使用WHERE。就像是:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
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.