Odwołanie się do aliasu kolumny w klauzuli WHERE


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

dostaję

„nieprawidłowa nazwa kolumny różnica dni”.

Maxlogtm to pole typu data i godzina. To małe rzeczy, które doprowadzają mnie do szaleństwa.


nie jestem pewien dla mysql, ale może alias musi być zawarty w tickach `daysdiff`.
— Ash Burlaczenko

Odpowiedzi:


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

Zwykle nie można odwoływać się do aliasów pól w WHEREklauzuli. (Potraktuj to jako całość, w SELECTtym aliasy, stosuje się poWHERE klauzuli.)

Ale, jak wspomniano w innych odpowiedziach, możesz zmusić SQL do SELECTobsługi traktowania przed WHEREklauzulą. Zwykle robi się to z nawiasami, aby wymusić logiczną kolejność operacji lub za pomocą wspólnego wyrażenia tabelowego (CTE):

Nawias / Podselekcja:

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

Lub zobacz odpowiedź Adama na wersję CTE tego samego.


16
Nie jest to możliwe bezpośrednio, ponieważ chronologicznie WHERE dzieje się przed SELECT, co zawsze jest ostatnim krokiem w łańcuchu wykonywania. REFER - stackoverflow.com/questions/356675/…
— david Blaine

afaik, jeśli alias w zaznaczeniu jest skorelowanym podzapytaniem, zadziała, podczas gdy rozwiązanie CTE nie.
— Răzvan Flavius ​​Panda

Jak wspomniał Pascal w swojej odpowiedzi tutaj stackoverflow.com/a/38822328/282887 , możesz użyć klauzuli HAVING, która wydaje się działać szybciej niż podzapytania.
— Bakhtiyor

@Bakhtiyor HAVINGOdpowiedź nie działa w większości środowisk SQL, w tym w MS-SQL, którego dotyczy to pytanie. (W T-SQL HAVINGwymaga funkcji agregującej.)
— Jamie F

72

Jeśli chcesz użyć aliasu w swojej WHEREklauzuli, musisz zawinąć go w sub select lub 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
Czy wiesz, jak te targi są efektywne? Czy użycie CTE wiąże się z dodatkowymi kosztami?
— James,

5
CTE jest po prostu ładniejszą składnią dla zapytania podrzędnego, więc wydajność byłaby podobna do tej. Z mojego doświadczenia wynika, że ​​różnica w wydajności nie była czymś, co mnie niepokoiło w przypadku takich operacji, ale powinno być dość proste przetestowanie tego w swoim środowisku, aby sprawdzić, czy ta konkretna tabela / zapytanie nie ma niekorzystnego wpływu na to, a nie wywołanie funkcji formuła w szczególności w klauzuli where. Podejrzewam, że nie zauważysz różnicy.
— Adam Wenger,

CTE są super ładne, dopóki nie spróbujesz ich użyć jako podzapytania. musiałem uciec się do tworzenia ich jako widoków, aby je zagnieździć. Uważam to za poważną wadę SQL
— symbiont

10

Najskuteczniejszym sposobem na zrobienie tego bez powtarzania kodu jest użycie HAVING zamiast WHERE

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

1
Myślę, że używanie HAVINGaliasów nie jest standardem (działa jednak na MySQL). W szczególności myślę, że nie działa z 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

Jeśli nie chcesz wyświetlać wszystkich swoich kolumn w CTE, możesz to zrobić w inny sposób 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

A co powiesz na użycie podzapytania (to zadziałało w MySQL)?

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

4

MAJĄC działa w MySQL zgodnie z dokumentacją:

BIORĄC klauzula został dodany do SQL ponieważ GDZIE Hasło nie może być używany z funkcji agregujących.


4

Możesz odwołać się do aliasu kolumny, ale musisz go zdefiniować za pomocą 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

Plusy:

  • pojedyncza definicja wyrażenia (łatwiejsza w utrzymaniu / brak konieczności kopiowania-wklejania)
  • nie ma potrzeby pakowania całego zapytania w CTE / zapytanie zewnętrzne
  • możliwość odniesienia się w WHERE/GROUP BY/ORDER BY
  • możliwa lepsza wydajność (pojedyncze wykonanie)

1
warto wspomnieć, że działa tylko w SQL Server
— Martin Zinovsky

1
@MartinZinovsky Pytanie jest oznaczone tagiem sql-serveri t-sql:)
— Lukasz Szozda

0

Przyjechałem tu szuka czegoś podobnego do tego, ale z przypadku, gdy, a zakończył przy użyciu gdzie tak: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0może można użyć DATEDIFFw WHEREbezpośrednio. Coś jak:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.