Referindo-se a um Alias ​​de Coluna em uma Cláusula WHERE

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

eu recebo

"nome da coluna inválido daysdiff".

Maxlogtm é um campo de data e hora. São as pequenas coisas que me deixam louco.

user990016
fonte
Não tenho certeza para o mysql, mas talvez o alias precise ser envolvido em ticks `daysdiff`.
Ash Burlaczenko

Respostas:

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

Normalmente você não pode se referir a aliases de campo na WHEREcláusula. (Pense nisso como o todo, SELECTincluindo aliases, é aplicado após a WHEREcláusula.)

Mas, como mencionado em outras respostas, você pode forçar o SQL a tratar SELECTa ser tratado antes da WHEREcláusula. Isso geralmente é feito entre parênteses para forçar a ordem lógica de operação ou com uma Expressão de tabela comum (CTE):

Parênteses / Subseleção:

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

Ou veja a resposta de Adam para uma versão CTE do mesmo.

Jamie F
fonte
16
Isso não é possível diretamente, porque cronologicamente, WHERE acontece antes de SELECT, que sempre é a última etapa na cadeia de execução. REFER - stackoverflow.com/questions/356675/...
David Blaine
se o alias no select for uma subconsulta correlacionada, isso funcionará enquanto a solução CTE não.
Răzvan Flavius ​​Panda
Como Pascal mencionou em sua resposta aqui stackoverflow.com/a/38822328/282887 , você pode usar a cláusula HAVING, que parece funcionar mais rápido que as subconsultas.
Bakhtiyor 26/03/19
@Bakhtiyor A HAVINGresposta não funciona na maioria dos ambientes SQL, incluindo o MS-SQL, sobre o qual esta pergunta se refere. (Na t-SQL, HAVINGrequer uma função agregada.)
Jamie F
72

Se você quiser usar o alias na sua WHEREcláusula, precisará envolvê-lo em uma sub-seleção ou 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
Adam Wenger
fonte
2
Você sabe como isso é eficiente em termos de eficiência? Existe sobrecarga extra usando um CTE?
James
5
Uma CTE é apenas uma sintaxe mais bonita para uma subconsulta, portanto, o desempenho seria semelhante a isso. Na minha experiência, a diferença de desempenho não me preocupou em operações como essa, mas deve ser bastante simples testá-la em seu ambiente para ver se sua tabela / consulta específica é afetada negativamente com isso. fórmula especificamente na cláusula where. Eu suspeito que você não notará diferença.
Adam Wenger
CTEs são super legais até você tentar usar um como uma subconsulta. Eu tive que recorrer a criá-los como vistas para aninhar-los. Eu considero isso uma grave lacuna SQL
simbionte
10

A maneira mais eficaz de fazer isso sem repetir seu código é usar HAVING em vez de WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120
Pascal
fonte
1
Eu acho que o uso HAVINGde aliases não é padrão (embora funcione no MySQL). Especificamente, acho que não funciona com o 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

Se você não deseja listar todas as suas colunas no CTE, outra maneira de fazer isso seria usar 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
Roman Pekar
fonte
6

Que tal usar uma subconsulta (isso funcionou para mim no Mysql)?

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

TENDO trabalha no MySQL de acordo com a documentação:

A cláusula HAVING foi adicionada ao SQL porque a palavra-chave WHERE não pôde ser usada com funções agregadas.

roier.rdz
fonte
4

Você pode consultar o alias da coluna, mas precisa defini-lo usando 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 Demo

Prós:

  • definição única de expressão (mais fácil de manter / sem necessidade de copiar e colar)
  • não há necessidade de agrupar toda a consulta com CTE / outerquery
  • possibilidade de se referir em WHERE/GROUP BY/ORDER BY
  • possível melhor desempenho (execução única)
Lukasz Szozda
fonte
1
vale a pena mencionar que ele só funciona no SQL Server
Martin Zinovsky
1
@MartinZinovsky Pergunta é marcado com sql-servere t-sql:)
Lukasz Szozda
0

Vim aqui procurando algo semelhante a isso, mas com um caso quando, e acabou usando a onde assim: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0talvez você poderia usar DATEDIFFno WHEREdiretamente. Algo como:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
Scy
fonte