Facendo riferimento a un alias di colonna in una clausola WHERE


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

ottengo

"nome colonna non valido daysdiff".

Maxlogtm è un campo datetime. Sono le piccole cose che mi fanno impazzire.


non sono sicuro per mysql, ma forse l'alias deve essere racchiuso tra le zecche `daysdiff`.
Ash Burlaczenko,

Risposte:


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

Normalmente non è possibile fare riferimento agli alias di campo nella WHEREclausola. (Pensa a come l'intero SELECTalias incluso, viene applicato dopo la WHEREclausola.)

Ma, come menzionato in altre risposte, puoi forzare SQL a trattare SELECTper essere gestito prima della WHEREclausola. Questo di solito viene fatto con parentesi per forzare l'ordine logico di operazione o con una Common Table Expression (CTE):

Parentesi / Sottoseleziona:

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

Oppure vedi la risposta di Adam per una versione CTE della stessa.


16
Questo non è possibile direttamente, perché cronologicamente, DOVE accade prima di SELEZIONA, che è sempre l'ultimo passo nella catena di esecuzione. RIFERIMENTO - stackoverflow.com/questions/356675/…
David Blaine

afaik se l'alias nella selezione è una sottoquery correlata funzionerà mentre la soluzione CTE no.
Răzvan Flavius ​​Panda,

Come Pascal ha menzionato nella sua risposta qui stackoverflow.com/a/38822328/282887 , è possibile utilizzare la clausola HAVING che sembra funzionare più velocemente delle subquery.
Bakhtiyor,

@Bakhtiyor La HAVINGrisposta non funziona nella maggior parte degli ambienti SQL, incluso MS-SQL di cui tratta questa domanda. (In T-SQL, HAVINGrichiede una funzione aggregata.)
Jamie F

72

Se si desidera utilizzare l'alias nella WHEREclausola, è necessario racchiuderlo in una sottoselezione o 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
Sai per caso quanto sia efficiente questa fiera? C'è un sovraccarico extra usando un CTE?
James,

5
Un CTE è solo una sintassi più carina per una sottoquery, quindi le prestazioni sarebbero simili. Nella mia esperienza, la differenza di prestazioni non è stata una cosa che mi ha preoccupato per operazioni come questa, ma dovrebbe essere abbastanza semplice testarlo nel proprio ambiente per vedere se la propria tabella / query specifica è influenzata negativamente rispetto a quella di chiamare il formula specifica nella clausola where. Sospetto che non noterai alcuna differenza.
Adam Wenger,

I CTE sono molto belli fino a quando non si tenta di utilizzarne uno come subquery. ho dovuto ricorrere alla loro creazione come vista per nidificarli. lo considero un grave difetto di SQL
symbiont,

10

Il modo più efficace per farlo senza ripetere il codice è l'uso di HAVING anziché WHERE

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

1
Penso che l'uso di HAVINGalias non sia standard (funziona su MySQL, però). In particolare, penso che non funzioni con 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 non vuoi elencare tutte le tue colonne in CTE, un altro modo per farlo sarebbe usare 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

Che ne dici di usare una subquery (questo ha funzionato per me in Mysql)?

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

4

HAVING funziona in MySQL secondo la documentazione:

La clausola HAVING è stata aggiunta a SQL perché non è stato possibile utilizzare la parola chiave WHERE con funzioni di aggregazione.


4

È possibile fare riferimento all'alias di colonna ma è necessario definirlo utilizzando 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

Professionisti:

  • definizione singola di espressione (più facile da mantenere / nessuna necessità di copiare e incollare)
  • non è necessario eseguire il wrapping dell'intera query con CTE / outerquery
  • possibilità di fare riferimento WHERE/GROUP BY/ORDER BY
  • possibile migliore prestazione (esecuzione singola)

1
vale la pena ricordare che funziona solo in SQL Server
Martin Zinovsky,

1
@MartinZinovsky La domanda è taggata con sql-servere t-sql:)
Lukasz Szozda,

0

Sono venuto qui in cerca qualcosa di simile a questo, ma con un caso in cui, e si è concluso con il quale in questo modo: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0forse si potrebbe usare DATEDIFFin WHEREdiretta. Qualcosa di simile a:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.