Verweisen auf einen Spaltenalias in einer WHERE-Klausel

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

Ich bekomme

"ungültiger Spaltenname daysdiff".

Maxlogtm ist ein Datum / Uhrzeit-Feld. Es sind die kleinen Dinge, die mich verrückt machen.

user990016
quelle
Ich bin mir nicht sicher für MySQL, aber vielleicht muss der Alias ​​in Ticks eingeschlossen werden `daysdiff`.
Ash Burlaczenko

Antworten:

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

Normalerweise können Sie in der WHEREKlausel nicht auf Feldaliasnamen verweisen . (Betrachten Sie es als das gesamte SELECTeinschließlich Aliase, wird nach der WHEREKlausel angewendet .)

Wie in anderen Antworten erwähnt, können Sie jedoch die Behandlung SELECTvon SQL vor der WHEREKlausel erzwingen . Dies erfolgt normalerweise in Klammern, um die logische Reihenfolge der Operationen zu erzwingen, oder mit einem Common Table Expression (CTE):

Klammer / Unterauswahl:

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

Oder sehen Sie Adams Antwort für eine CTE-Version derselben.

Jamie F.
quelle
15
Dies ist nicht direkt möglich, da chronologisch WHERE vor SELECT geschieht, was immer der letzte Schritt in der Ausführungskette ist. REFER - stackoverflow.com/questions/356675/…
David Blaine
afaik Wenn der Alias ​​in der Auswahl eine korrelierte Unterabfrage ist, funktioniert dies, während die CTE-Lösung dies nicht tut.
Răzvan Flavius ​​Panda
Wie Pascal in seiner Antwort hier erwähnt hat , können Sie die HAVING-Klausel verwenden, die schneller zu funktionieren scheint als Unterabfragen.
Bakhtiyor
@ Bakhtiyor Die HAVINGAntwort funktioniert in den meisten SQL-Umgebungen nicht, einschließlich MS-SQL, um das es in dieser Frage geht. (In T-SQL HAVINGerfordert eine Aggregatfunktion.)
Jamie F
71

Wenn Sie den Alias ​​in Ihrer WHEREKlausel verwenden möchten , müssen Sie ihn in eine Unterauswahl oder einen CTE einschließen :

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
quelle
2
Wissen Sie zufällig, wie effizient diese Messen sind? Gibt es zusätzlichen Overhead bei Verwendung eines CTE?
James
5
Ein CTE ist nur eine schönere Syntax für eine Unterabfrage, daher wäre die Leistung ähnlich. Nach meiner Erfahrung hat mich der Leistungsunterschied bei solchen Vorgängen nicht beschäftigt, aber es sollte ziemlich einfach sein, ihn in Ihrer Umgebung zu testen, um festzustellen, ob Ihre spezifische Tabelle / Abfrage davon nachteilig beeinflusst wird, im Vergleich zum Aufrufen von Formel speziell in der where-Klausel. Ich vermute, Sie werden keinen Unterschied bemerken.
Adam Wenger
CTEs sind super nett, bis Sie versuchen, eine als Unterabfrage zu verwenden. Ich musste darauf zurückgreifen, sie als Ansichten zu erstellen, um sie zu verschachteln. Ich halte dies für ein ernstes SQL-Manko
Symbiont
10

Der effektivste Weg, dies zu tun, ohne Ihren Code zu wiederholen, ist die Verwendung von HAVING anstelle von WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120
Pascal
quelle
1
Ich denke, die Verwendung HAVINGvon Aliasen ist kein Standard (funktioniert jedoch unter MySQL). Insbesondere denke ich, dass es mit SQL Server nicht funktioniert.
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

Wenn Sie nicht alle Ihre Spalten in CTE auflisten möchten, können Sie dies folgendermaßen tun 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
quelle
6

Wie wäre es mit einer Unterabfrage (dies hat bei mir in MySQL funktioniert)?

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

HAVING funktioniert in MySQL gemäß Dokumentation:

Die HAVING- Klausel wurde zu SQL hinzugefügt, da das WHERE-Schlüsselwort nicht mit Aggregatfunktionen verwendet werden konnte.

roier.rdz
quelle
4

Sie können auf Spaltenalias verweisen, müssen ihn jedoch wie folgt definieren 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

Vorteile:

  • einzelne Definition des Ausdrucks (einfacher zu pflegen / kein Kopieren und Einfügen erforderlich)
  • Es ist nicht erforderlich, die gesamte Abfrage mit CTE / Outerquery zu versehen
  • Möglichkeit, sich zu beziehen WHERE/GROUP BY/ORDER BY
  • mögliche bessere Leistung (Einzelausführung)
Lukasz Szozda
quelle
1
Es ist erwähnenswert, dass es nur in SQL Server funktioniert
Martin
1
@ MartinZinovsky Frage ist markiert mit sql-serverund t-sql:)
Lukasz Szozda
0

Kam hierher und sah ähnlich aus, aber mit einem CASE WHEN, und beendete die Verwendung des Wo wie folgt: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0Vielleicht könnten Sie DATEDIFFin der WHEREdirekt verwenden. Etwas wie:

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