¿Cómo puedo incluir valores nulos en un MIN o MAX?


Tengo una tabla donde estoy almacenando datos de intervalos de tiempo. la tabla tiene un esquema similar a:

ID INT NOT NULL IDENTITY(1,1)   
RecordID INT NOT NULL  
StartDate DATE NOT NULL  
EndDate DATE NULL  

Y estoy tratando de calcular las fechas de inicio y finalización para cada id de registro, por lo que la fecha de inicio mínima y la fecha de finalización máxima. startDate no es nullable, así que no tengo que preocuparme por esto, pero necesito el MAX(endDate) para indicar que esto es actualmente un intervalo de tiempo en ejecución.

Es importante que mantenga el valor NULL de endDate y lo trate como el valor máximo.

El el intento más simple (abajo) no funciona resaltando el problema de que MIN y MAX ignorarán los NULLS (fuente: http://technet.microsoft.com/en-us/library/ms179916.aspx).

SELECT recordid, MIN(startdate), MAX(enddate) FROM tmp GROUP BY recordid

He creado un violín SQL con la configuración básica hecha.

Http://sqlfiddle.com/#! 3 / b0a75

¿Cómo puedo doblar SQL Server 2008 a mi voluntad para producir el siguiente resultado a partir de los datos dados en el SQLFiddle?

RecordId  Start       End  
1         2009-06-19  NULL
2         2012-05-06  NULL
3         2013-01-25  NULL
4         2004-05-06  2009-12-01
Author: Cœur, 2014-01-22

7 answers

Es un poco feo, pero debido a que las NULLs tienen un significado especial para ti, esta es la forma más limpia que se me ocurre para hacerlo:

SELECT recordid, MIN(startdate),
   CASE WHEN MAX(CASE WHEN enddate IS NULL THEN 1 ELSE 0 END) = 0
        THEN MAX(enddate)
   END
FROM tmp GROUP BY recordid

Es decir, si cualquier fila tiene un NULL, queremos forzar que sea la respuesta. Solo si ninguna fila contiene un NULL debemos devolver el MIN (o MAX).

 48
Author: Damien_The_Unbeliever,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-22 15:15:06

El efecto que desea es tratar el NULL como la fecha más grande posible y luego reemplazarlo con NULL nuevamente al completarlo:

SELECT RecordId, MIN(StartDate), NULLIF(MAX(COALESCE(EndDate,'9999-12-31')),'9999-12-31') 
  FROM tmp GROUP BY RecordId

Por su violín esto devolverá los resultados exactos que especifique bajo todas las condiciones.

 29
Author: Matthew Erwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-27 03:50:04

En mi expresión - count (enddate) cuenta cuántas filas donde enddates no son null contar(*) contar cuántas filas totales Al comparar, puede saber fácilmente si alguna fecha final contiene null. Si son idénticos entonces max(enddate) es el resultado. De lo contrario, el caso devolverá null por defecto, que también es la respuesta. Esta es una forma muy popular de hacer esta verificación exacta.

SELECT recordid, 
MIN(startdate), 
case when count(enddate) = count(*) then max(enddate) end
FROM tmp 
GROUP BY recordid
 13
Author: t-clausen.dk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-23 09:57:19

Use IsNull

SELECT recordid, MIN(startdate), MAX(IsNull(enddate, Getdate()))
FROM tmp 
GROUP BY recordid

He modificado MIN en la segunda instrucción a MAX

 3
Author: Marko Juvančič,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-22 14:58:32

Suponiendo que solo tiene un registro con null en la columna endDate para un registro dado, algo como esto debería darte la salida deseada:

WITH cte1 AS
(
SELECT recordid, MIN(startdate) as min_start , MAX(enddate) as max_end
FROM tmp 
GROUP BY recordid
)

SELECT a.recordid, a.min_start , 
CASE 
   WHEN b.recordid IS  NULL THEN a.max_end
END as max_end
FROM cte1 a
LEFT JOIN tmp b ON (b.recordid = a.recordid AND b.enddate IS NULL)
 1
Author: a1ex07,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-22 15:23:26

Utilice la función analítica:

select case when 
    max(field) keep (dense_rank first order by datfin desc nulls first) is null then 1 
    else 0 end as flag 
from MYTABLE;
 0
Author: TheBakker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 12:09:05

Trato de usar una unión para combinar dos consultas para formatear los retornos que desea:

SELECT recordid, startdate, enddate FROM tmp Where enddate is null UNION SELECT recordid, MIN(startdate), MAX(enddate) FROM tmp GROUP BY recordid

Pero no tengo idea si el Sindicato tendría un gran impacto en el rendimiento

 -1
Author: SHO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-01 14:01:59