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.