sql >> Base de Datos >  >> RDS >> Sqlserver

Creación de grupos de días consecutivos que cumplen un criterio dado

En esta respuesta, asumiré que el campo "id" numera las filas consecutivamente cuando se ordenan por fecha creciente, como lo hace en los datos de ejemplo. (Dicha columna se puede crear si no existe).

Este es un ejemplo de una técnica descrita aquí y aquí .

1) Unir la tabla a sí misma en valores "id" adyacentes. Esto empareja filas adyacentes. Seleccione filas donde el campo "asignación" haya cambiado. Almacene el resultado en una tabla temporal, manteniendo también un índice en ejecución.

SET @idx = 0;
CREATE TEMPORARY TABLE boundaries
SELECT
   (@idx := @idx + 1) AS idx,
   a1.date AS prev_end,
   a2.date AS next_start,
   a1.allocation as allocation
FROM allocations a1
JOIN allocations a2
ON (a2.id = a1.id + 1)
WHERE a1.allocation != a2.allocation;

Esto le da una tabla que tiene "el final del período anterior", "el comienzo del próximo período" y "el valor de la 'asignación' en el período anterior" en cada fila:

+------+------------+------------+------------+
| idx  | prev_end   | next_start | allocation |
+------+------------+------------+------------+
|    1 | 2012-01-01 | 2012-01-02 |          0 |
|    2 | 2012-01-02 | 2012-01-03 |          2 |
|    3 | 2012-01-05 | 2012-01-06 |          0 |
+------+------------+------------+------------+

2) Necesitamos el inicio y el final de cada período en la misma fila, por lo que debemos combinar las filas adyacentes nuevamente. Haga esto creando una segunda tabla temporal como boundaries pero teniendo un idx campo 1 mayor:

+------+------------+------------+
| idx  | prev_end   | next_start |
+------+------------+------------+
|    2 | 2012-01-01 | 2012-01-02 |
|    3 | 2012-01-02 | 2012-01-03 |
|    4 | 2012-01-05 | 2012-01-06 |
+------+------------+------------+

Ahora únete al idx campo y obtenemos la respuesta:

SELECT
  boundaries2.next_start AS start,
  boundaries.prev_end AS end,
  allocation
FROM boundaries
JOIN boundaries2
USING(idx);

+------------+------------+------------+
| start      | end        | allocation |
+------------+------------+------------+
| 2012-01-02 | 2012-01-02 |          2 |
| 2012-01-03 | 2012-01-05 |          0 |
+------------+------------+------------+

** Tenga en cuenta que esta respuesta obtiene los períodos "internos" correctamente pero pierde los dos períodos de "borde" donde la asignación =0 al principio y la asignación =5 al final. Esos se pueden extraer usando UNION cláusulas pero quería presentar la idea central sin esa complicación.