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.