Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Създаване на групи от последователни дни, отговарящи на даден критерий

В този отговор ще приема, че полето „id“ номерира редовете последователно, когато са сортирани по нарастваща дата, както е в примерните данни. (Такава колона може да бъде създадена, ако не съществува).

Това е пример за техника, описана тук и тук .

1) Присъединете таблицата към себе си на съседни стойности на "id". Това сдвоява съседни редове. Изберете редове, където полето „разпределение“ е променено. Съхранявайте резултата във временна таблица, като също поддържате работещ индекс.

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;

Това ви дава таблица с „края на предишния период“, „началото на следващия период“ и „стойността на „разпределението“ в предишния период“ във всеки ред:

+------+------------+------------+------------+
| 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) Имаме нужда от началото и края на всеки период в един и същи ред, така че трябва да комбинираме съседни редове отново. Направете това, като създадете втора временна таблица като boundaries но с idx поле 1 по-голямо:

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

Сега се присъединете към idx и получаваме отговора:

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

** Обърнете внимание, че този отговор получава правилно "вътрешните" периоди, но пропуска двата "крайни" периода, където разпределението =0 в началото и разпределението =5 в края. Те могат да бъдат изтеглени чрез UNION клаузи, но исках да представя основната идея без това усложнение.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server Management Studio - Добавянето/преместването на колони изисква премахване и повторно създаване?

  2. .NET 4:Как да конфигурирате EDMX файл в друг сборник в Web.Config

  3. Въведение в OPENJSON с примери (SQL Server)

  4. Как да определим стойности за липсващи месеци въз основа на данни от предходни месеци в T-SQL

  5. Използвайки SSIS, как да намеря градовете с най-голямо население?