Ссылаясь на псевдоним столбца в предложении WHERE


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

я получил

msgstr "неверное имя столбца daysdiff".

Maxlogtm - это поле даты и времени. Это мелочи, которые сводят меня с ума.


не уверен для mysql, но, возможно, псевдоним должен быть обернут в галочки `daysdiff`.
Эш Бурлаченко

Ответы:


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

Обычно вы не можете ссылаться на псевдонимы полей в WHEREпредложении. (Думайте об этом как о всех, SELECTвключая псевдонимы, применяется после WHEREпункта.)

Но, как уже упоминалось в других ответах, вы можете заставить SQL обрабатываться SELECTдо обработки WHERE. Обычно это делается с помощью скобок для принудительного логического порядка операций или с помощью общего табличного выражения (CTE):

Скобки / подвыборки:

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

Или посмотрите ответ Адама для версии CTE того же самого.


16
Это невозможно напрямую, потому что в хронологическом порядке ГДЕ происходит перед SELECT, который всегда является последним шагом в цепочке выполнения. СМОТРИТЕ - stackoverflow.com/questions/356675/...
Дэвид Блейн

afaik, если псевдоним в select является коррелированным подзапросом, это будет работать, а решение CTE - нет.
Разван Флавиус Панда

Как отметил Паскаль в своем ответе здесь stackoverflow.com/a/38822328/282887 , вы можете использовать предложение HAVING, которое, кажется, работает быстрее, чем подзапросы.
Бахтиер

@Bakhtiyor HAVINGОтвет не работает в большинстве сред SQL, включая MS-SQL, о котором идет речь в этом вопросе. (В T-SQL HAVINGтребуется агрегатная функция.)
Джейми Ф

72

Если вы хотите использовать псевдоним в своем WHEREпредложении, вам нужно обернуть его в суб-выборку или 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
Вы случайно не знаете, насколько это эффективно? Есть ли дополнительные затраты при использовании CTE?
Джеймс

5
CTE - это просто более симпатичный синтаксис для подзапроса, поэтому производительность будет примерно такой. По моему опыту, разница в производительности не была чем-то, что меня интересовало для подобных операций, но должно быть довольно просто протестировать его в вашей среде, чтобы увидеть, не влияет ли это на вашу конкретную таблицу / запрос по сравнению с вызовом Формула конкретно в предложении, где. Я подозреваю, что вы не заметите разницу.
Адам Венгер

CTE очень хороши, пока вы не попытаетесь использовать их в качестве подзапроса. Мне пришлось прибегнуть к созданию их как представления, чтобы вложить их. я считаю это серьезным недостатком SQL
symbiont

10

Самый эффективный способ сделать это без повторения кода - использовать HAVING вместо WHERE.

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

1
Я думаю, что использование HAVINGпсевдонимов не является стандартным (хотя работает на MySQL). В частности, я думаю, что это не работает с SQL Server.
Tokland

2
SQL Server:[S0001][207] Invalid column name 'daysdiff'
Вадим

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.
Вадим

9

Если вы не хотите перечислять все свои столбцы в CTE, другой способ сделать это - использовать 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

Как насчет использования подзапроса (это работало для меня в Mysql)?

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

4

HAVING работает в MySQL в соответствии с документацией:

Предложение HAVING было добавлено в SQL, поскольку ключевое слово WHERE нельзя использовать с агрегатными функциями.


4

Вы можете ссылаться на псевдоним столбца, но вам нужно определить его, используя 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

Плюсы:

  • единое определение выражения (легче поддерживать / не нужно копировать-вставлять)
  • нет необходимости упаковывать весь запрос с помощью CTE / externalquery
  • возможность ссылки в WHERE/GROUP BY/ORDER BY
  • возможно лучшая производительность (одиночное исполнение)

1
Стоит отметить, что он работает только в SQL Server
Мартин Зиновский,

1
@MartinZinovsky Вопрос отмечен с sql-serverи t-sql:)
Лукаш Шозда

0

Приехал сюда в поисках что - то подобное, но с случаем , когда, и закончился , используя , где , как это: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0может быть , вы могли бы использовать DATEDIFFв WHEREнепосредственно. Что-то вроде:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.