Sql server 带中间记录的SQL Server最小最大值

Sql server 带中间记录的SQL Server最小最大值,sql-server,aggregate,aggregate-functions,Sql Server,Aggregate,Aggregate Functions,如果这个问题以前有人回答过,我很抱歉,但是我找不到它。也许是我的坏关键词 我有这张桌子: 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

如果这个问题以前有人回答过,我很抱歉,但是我找不到它。也许是我的坏关键词

我有这张桌子:

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
此表中的结果:

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
< P> >我想创建一个结果表,用<<代码>带和最小<代码>开始日期< /代码>和最大<代码>结束日期<代码>对每个<代码>雇员<代码>进行分组,但是当中间记录(<代码>带< /代码>)存在于类似的<代码>带<代码>中间时,应限制
结束日期
,并再次重置类似
波段
中下一组的
开始日期

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获得每个波段的最大值和最小值,并将其与原始表格进行比较,但仍然失败。我也试过使用超前和滞后,但还是失败了

很高兴拥有

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])
假设第二条记录的
EndDate
2012-02-01
,我希望第一组的结果仍然是一条记录

Employee   Band   StartDate   EndDate
----------------------------------------
Emp1       Band1  2009-01-01  2013-08-31
由于结果的每一行仅在
波段中有所不同
,因此我能够计算出一名员工在转到另一波段(不同波段)之前在某个波段停留了多长时间


但拥有它是件好事。

这通常被称为缺口和孤岛

一种方法

示例

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将产生以下结果

请注意标志和组列


显然,每当员工更改波段时,您都希望对行进行分组。这是直接使用窗口函数实现的。以下解决方案在标注栏更改时向行添加“更改”标志。请注意,它忽略了间隙。将DATEDIFF check添加到case语句中,以查找此人与乐队关联的实际时间:

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

如果您想了解其工作原理,这是中间结果:

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

样本数据最好作为+。请将您的问题包括在内以及您当前的尝试。此外,请用文字说明获得所需结果的逻辑。关于更多细节,我希望现在更好,更好。干得好!如果两个记录之间存在间隙怎么办?假设第二条记录的开始日期为
2011-02-01
,您希望的结果是否忽略了这一差距,或者它是否包含数据中这两条记录的
emp1
band1
的两条记录?编辑了该问题。谢谢你指出。我宁愿结果忽略这个差距,仍然为第一组输出一个记录。哇!谢谢你的关键词。现在我无法访问我的工作站。一旦我试过你的逻辑,我会让你知道的。到目前为止,我的想法是基于你的解决方案。我会在接下来的11小时内回复你。谢谢你的解决方案!我已经尝试过了,当记录之间有差距时,效果非常好。然而,即使存在差距,我也需要将它们分组。很抱歉,我以前没有详细说明这一点。我相信你的回答会帮助别人!谢谢你的回答!它完美地解决了我目前的问题。对于那些需要考虑记录之间的差距的人来说,约翰的解决方案非常有效。