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.


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.


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

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

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

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

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.


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)

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.