sql >> Databáze >  >> RDS >> Sqlserver

Vytváření skupin po sobě jdoucích dnů splňujících daná kritéria

V této odpovědi budu předpokládat, že pole „id“ čísluje řádky postupně při řazení podle rostoucího data, jako je tomu v příkladech dat. (Takový sloupec lze vytvořit, pokud neexistuje).

Toto je příklad techniky popsané zde a zde .

1) Připojte tabulku k sobě na sousední hodnoty "id". Tím se spárují sousední řádky. Vyberte řádky, kde se pole "allocation" změnilo. Uložte výsledek do dočasné tabulky a udržujte také běžící index.

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;

Získáte tak tabulku, která má v každém řádku „konec předchozího období“, „začátek dalšího období“ a „hodnotu „přidělení“ v předchozím období:

+------+------------+------------+------------+
| 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) Potřebujeme začátek a konec každé periody ve stejné řadě, takže musíme znovu spojit sousední řady. Udělejte to vytvořením druhé dočasné tabulky, jako je boundaries ale mající idx pole 1 větší:

+------+------------+------------+
| 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 |
+------+------------+------------+

Nyní se připojte na idx pole a dostaneme odpověď:

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 |
+------------+------------+------------+

** Všimněte si, že tato odpověď dostane „interní“ období správně, ale chybí dvě „okrajová“ období, kde přidělení =0 na začátku a přidělení =5 na konci. Ty lze stáhnout pomocí UNION klauzule, ale chtěl jsem prezentovat základní myšlenku bez této komplikace.



  1. Podivné chování skupiny v dotazu, které je třeba optimalizovat

  2. SQL dotaz pro výběr dat mezi dvěma daty

  3. Jak spustit dotaz SQLite asynchronně na vláknu na pozadí?

  4. PŘÍPAD Mysql NENÍ NALEZEN pro CASE STATEMENT na uložené proceduře