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.


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.


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

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

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

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

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.


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)

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.