SQL Server min max с промежуточной записью - PullRequest
0 голосов
/ 13 октября 2018

Извините, если на этот вопрос уже был дан ответ, но я не могу его найти.Возможно из моих плохих ключевых слов.

У меня есть эта таблица:

CREATE TABLE test1 
(
    Employee VARCHAR(10),
    Band VARCHAR(10),
    StartDate DATE,
    EndDate DATE
)

INSERT INTO test1 
VALUES ('Emp1', 'Band1', '2009-01-01', '2010-12-31'),
       ('Emp1', 'Band1', '2011-01-01', '2012-12-31'), 
       ('Emp1', 'Band1', '2013-01-01', '2013-08-31'),
       ('Emp1', 'Band2', '2013-09-01', '2013-12-31'),
       ('Emp1', 'Band2', '2014-01-01', '2014-06-30'),
       ('Emp1', 'Band1', '2014-07-01', '2014-12-31'),
       ('Emp1', 'Band1', '2015-01-01', '2018-08-31'),
       ('Emp2', 'Band1', '2012-01-01', '2014-12-31'),
       ('Emp2', 'Band1', '2015-01-01', '2018-03-31')

Результаты в этой таблице:

Employee   Band   StartDate   EndDate
----------------------------------------
Emp1       Band1  2009-01-01  2010-12-31
Emp1       Band1  2011-01-01  2012-12-31
Emp1       Band1  2013-01-01  2013-08-31
Emp1       Band2  2013-09-01  2013-12-31
Emp1       Band2  2014-01-01  2014-06-30
Emp1       Band1  2014-07-01  2014-12-31
Emp1       Band1  2015-01-01  2018-08-31
Emp2       Band1  2012-01-01  2014-12-31
Emp2       Band1  2015-01-01  2018-03-31

Я хочу создать группу результатов таблицыкаждый employee с band и минимальным start date и максимальным end date, но когда промежуточная запись (band) существует в середине между аналогичными band, end date должен быть ограничен, а start date следующей группы в аналогичном band должен быть сброшен снова.

Employee   Band   StartDate   EndDate
----------------------------------------
Emp1       Band1  2009-01-01  2013-08-31
Emp1       Band2  2013-09-01  2014-06-30
Emp1       Band1  2014-07-01  2018-08-31
Emp2       Band1  2012-01-01  2018-03-31

Я пытался получить CTE, чтобы получить максимум и минимум каждой полосы и сравнить ее сОригинальная таблица, но я все равно не смог.Я также пытался использовать опережающие и запаздывающие сигналы, но все равно не получалось.

Приятно иметь

Предположим, что EndDate второй записи 2012-02-01,Я предпочитаю, чтобы результат был по-прежнему одной записью для первой группы Band1.

Employee   Band   StartDate   EndDate
----------------------------------------
Emp1       Band1  2009-01-01  2013-08-31

Поскольку каждая строка результата отличается только на Band, я смог бы выяснить, как долго сотрудник находился вопределенная группа, прежде чем перейти в другую (другую группу).

Но это что-то хорошее, что есть.

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Очевидно, вы хотите группировать строки всякий раз, когда сотрудник меняет группу.Это прямо с оконными функциями.Следующее решение добавляет флаг «изменение» в строки при каждом изменении диапазона.Имейте в виду, что он игнорирует пробелы.Добавьте проверку DATEDIFF в выписку по делу, чтобы найти фактическое количество времени, в течение которого человек был связан с группой:

DECLARE @test1 TABLE(
    Employee VARCHAR(10),
    Band VARCHAR(10),
    StartDate DATE,
    EndDate DATE
);

INSERT INTO @test1 VALUES
('Emp1', 'Band1', '2009-01-01', '2010-12-31'),
('Emp1', 'Band1', '2011-01-01', '2012-12-31'),
('Emp1', 'Band1', '2013-01-01', '2013-08-31'),
('Emp1', 'Band2', '2013-09-01', '2013-12-31'),
('Emp1', 'Band2', '2014-01-01', '2014-06-30'),
('Emp1', 'Band1', '2014-07-01', '2014-12-31'),
('Emp1', 'Band1', '2015-01-01', '2018-08-31'),
('Emp2', 'Band1', '2012-01-01', '2014-12-31'),
('Emp2', 'Band1', '2015-01-01', '2018-03-31');

WITH cte1 AS (
    SELECT *,
        CASE WHEN LAG(Band) OVER (PARTITION BY Employee ORDER BY StartDate) = Band /* AND DATEDIFF(...) */ THEN 0 ELSE 1 END AS Chg
    FROM @test1
), cte2 AS (
    SELECT *,
        SUM(Chg) OVER (PARTITION BY Employee ORDER BY StartDate) AS Grp
    FROM cte1
)
SELECT Employee, Band, MIN(StartDate), Max(EndDate)
FROM cte2
GROUP BY Employee, Band, Grp

DB Fiddle

Это промежуточный результат, если вы хотите увидеть, как он работает:

| Employee | Band  | StartDate           | EndDate             | Chg | Grp |
|----------|-------|---------------------|---------------------|-----|-----|
| Emp1     | Band1 | 01/01/2009 00:00:00 | 31/12/2010 00:00:00 | 1   | 1   |
| Emp1     | Band1 | 01/01/2011 00:00:00 | 31/12/2012 00:00:00 | 0   | 1   |
| Emp1     | Band1 | 01/01/2013 00:00:00 | 31/08/2013 00:00:00 | 0   | 1   |
| Emp1     | Band2 | 01/09/2013 00:00:00 | 31/12/2013 00:00:00 | 1   | 2   |
| Emp1     | Band2 | 01/01/2014 00:00:00 | 30/06/2014 00:00:00 | 0   | 2   |
| Emp1     | Band1 | 01/07/2014 00:00:00 | 31/12/2014 00:00:00 | 1   | 3   |
| Emp1     | Band1 | 01/01/2015 00:00:00 | 31/08/2018 00:00:00 | 0   | 3   |
| Emp2     | Band1 | 01/01/2012 00:00:00 | 31/12/2014 00:00:00 | 1   | 1   |
| Emp2     | Band1 | 01/01/2015 00:00:00 | 31/03/2018 00:00:00 | 0   | 1   |
0 голосов
/ 13 октября 2018

Это обычно известно как Гапсы и острова .

Один подход

Пример

Declare @YourTable Table ([Employee] varchar(50),[Band] varchar(50),[Start] date,[End] date)
Insert Into @YourTable Values 
 ('Emp1','Band1','2009-01-01','2010-12-31')
,('Emp1','Band1','2011-01-01','2012-12-31')
,('Emp1','Band1','2013-01-01','2013-08-31')
,('Emp1','Band2','2013-09-01','2013-12-31')
,('Emp1','Band2','2014-01-01','2014-06-30')
,('Emp1','Band1','2014-07-01','2014-12-31')
,('Emp1','Band1','2015-01-01','2018-08-31')
,('Emp2','Band3','2012-01-01','2014-12-31')
,('Emp2','Band3','2015-01-01','2018-03-31')

;with cte as (
Select *,Grp = sum(Flg) over (Partition By Employee Order by [End])
 From (
        Select *,Flg = IsNull(datediff(DAY,Lag([End],1) over (Partition By Employee,Band Order by [End]) ,[Start]) - 1,1)
         From  @YourTable
      ) A
)
Select Employee
      ,Band
      ,[Start] = min([Start])
      ,[End]   = max([End])
 From cte
 Group By Employee,Band,Grp
 Order by Employee,max([End])

Возвращает

Employee    Band    Start       End
Emp1        Band1   2009-01-01  2013-08-31
Emp1        Band2   2013-09-01  2014-06-30
Emp1        Band1   2014-07-01  2018-08-31
Emp2        Band3   2012-01-01  2018-03-31

Если это помогает с визуализацией, CTE создает следующие

Обратите внимание на флаг и столбцы группы

enter image description here

...