Refiriéndose a un alias de columna en una cláusula WHERE

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

yo obtengo

"nombre de columna inválido daysdiff".

Maxlogtm es un campo de fecha y hora. Son las pequeñas cosas que me vuelven loco.

usuario990016
fuente
no estoy seguro de mysql, pero tal vez el alias debe estar envuelto en ticks `daysdiff`.
Ash Burlaczenko

Respuestas:

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

Normalmente no puede hacer referencia a los alias de campo en la WHEREcláusula. (Piense en ello como todo el SELECTalias incluido, se aplica después de la WHEREcláusula).

Pero, como se menciona en otras respuestas, puede forzar el tratamiento de SQL para SELECTque se maneje antes de la WHEREcláusula. Esto generalmente se hace con paréntesis para forzar el orden lógico de operación o con una expresión de tabla común (CTE):

Paréntesis / Subselección:

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

O vea la respuesta de Adam para una versión CTE de la misma.

Jamie F
fuente
16
Esto no es posible directamente, porque cronológicamente, DÓNDE sucede antes de SELECCIONAR, que siempre es el último paso en la cadena de ejecución. REFER - stackoverflow.com/questions/356675/…
david blaine
afaik si el alias en la selección es una subconsulta correlacionada, esto funcionará mientras que la solución CTE no lo hará.
Răzvan Flavius ​​Panda
Como Pascal mencionó en su respuesta aquí stackoverflow.com/a/38822328/282887 , puede usar la cláusula HAVING que parece funcionar más rápido que las subconsultas.
Bakhtiyor
@Bakhtiyor La HAVINGrespuesta no funciona en la mayoría de los entornos SQL, incluido MS-SQL sobre el que trata esta pregunta. (En T-SQL, HAVINGrequiere una función agregada.)
Jamie F
72

Si desea utilizar el alias en su WHEREcláusula, debe ajustarlo en una sub selección, 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
Adam Wenger
fuente
2
¿Sabes cómo funciona esta feria de eficiencia? ¿Hay gastos generales adicionales usando un CTE?
James
55
Un CTE es una sintaxis más bonita para una subconsulta, por lo que el rendimiento sería similar. En mi experiencia, la diferencia de rendimiento no ha sido algo que me haya preocupado por operaciones como esta, pero debería ser bastante simple probarlo en su entorno para ver si su tabla / consulta específica se ve afectada negativamente con esto en lugar de llamar al fórmula específicamente en la cláusula where. Sospecho que no notarás una diferencia.
Adam Wenger
Los CTE son súper agradables hasta que intentes usar uno como subconsulta. He tenido que recurrir a crearlos como vistas para anidarlos. Considero que esto es una grave deficiencia de SQL
simbionte
10

La forma más efectiva de hacerlo sin repetir su código es usar HAVING en lugar de WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120
Pascal
fuente
1
Creo que usar HAVINGalias no es estándar (aunque funciona en MySQL). Específicamente, creo que no funciona 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

Si no desea enumerar todas sus columnas en CTE, otra forma de hacerlo sería usar 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
fuente
6

¿Qué tal usar una subconsulta (esto funcionó para mí en Mysql)?

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

HABER funciona en MySQL de acuerdo con la documentación:

La cláusula HAVING se agregó a SQL porque la palabra clave WHERE no se pudo usar con funciones agregadas.

roier.rdz
fuente
4

Puede hacer referencia al alias de columna, pero debe definirlo usando 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

Pros:

  • definición única de expresión (más fácil de mantener / sin necesidad de copiar y pegar)
  • no es necesario ajustar toda la consulta con CTE / externalquery
  • posibilidad de referirse en WHERE/GROUP BY/ORDER BY
  • posible mejor rendimiento (ejecución única)
Lukasz Szozda
fuente
1
vale la pena mencionar que solo funciona en SQL Server
Martin Zinovsky
1
@MartinZinovsky La pregunta está etiquetada con sql-servery t-sql:)
Lukasz Szozda
0

Vine aquí buscando algo similar a eso, pero con un caso cuando, y terminó usando el dónde de esta manera: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0tal vez se podría utilizar DATEDIFFen el WHEREdirectamente. Algo como:

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