从年度条目创建范围映射记录

时间:2018-02-06 19:20:29

标签: sql sql-server database

我有一个表,它会随着时间的推移将ID映射到关联ID(AssocID),并且数据库的构建每年只有一条记录。我想在每个关联期间累积一张记录。

当前示例:

    ID AssocID Start End
    1  a       2000  2001
    1  a       2001  2002
    1  b       2002  2003
    1  b       2003  2004
    1  a       2004  2005
    ...
    1  a       2017  2018
    2  c       2000  2001
    2  c       2001  2002
    2  d       2002  2003
    ...
    2  d       2017  2018

我试图让它看起来更像这样:

    ID AssocID Start End
    1  a       2000  2002
    1  b       2002  2004
    1  a       2004  2018
    2  c       2000  2002
    2  d       2002  2018

我的主要问题是ID'1'会在一段时间后回到AssocID'a'并使用DISTINCT(ID,AssocID)和MIN(Start)错过第二次ID'1'映射到AssocID'a'

任何帮助表示赞赏:)

2 个答案:

答案 0 :(得分:1)

你可以使用它。

 -- Sample Data

 DECLARE @MyTable TABLE (ID INT, AssocID VARCHAR(10),  Start INT, [End] INT)
 INSERT INTO @MyTable VALUES
(1, 'a', 2000, 2001),
(1, 'a', 2001, 2002),
(1, 'b', 2002, 2003),
(1, 'b', 2003, 2004),
(1, 'a', 2004, 2005),
(1, 'a', 2017, 2018),
(2, 'c', 2000, 2001),
(2, 'c', 2001, 2002),
(2, 'd', 2002, 2003),
(2, 'd', 2017, 2018)

-- Query 

SELECT ID, AssocID, MIN(Start) [Start], MAX([End]) [End] FROM 
    ( SELECT *, 
        GRP = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Start) - ROW_NUMBER() OVER(PARTITION BY ID, AssocID ORDER BY Start)
     FROM @MyTable ) T
GROUP BY ID, AssocID, GRP
ORDER BY ID,  [Start]

结果:

ID          AssocID    Start       End
----------- ---------- ----------- -----------
1           a          2000        2002
1           b          2002        2004
1           a          2004        2018
2           c          2000        2002
2           d          2002        2018

答案 1 :(得分:1)

这是间隙和岛屿问题的一个例子。您需要首先确定每个小组的开始grp_start,然后group by每个grp以找到min / max

declare @T table (ID int, AssocID varchar(3), Start int, [End] int)
insert into @T (ID, AssocID, Start, [End]) values
(1, 'a', 2000, 2001),(1, 'a', 2001, 2002),(1, 'b', 2002, 2003),(1, 'b', 2003, 2004),(1, 'a', 2004, 2005),(1, 'a', 2005, 2006),(1, 'a', 2006, 2007),(1, 'a', 2007, 2008),(1, 'a', 2008, 2009),(1, 'a', 2009, 2010),(1, 'a', 2010, 2011),(1, 'a', 2011, 2012),(1, 'a', 2012, 2013),(1, 'a', 2013, 2014),(1, 'a', 2014, 2015),(1, 'a', 2015, 2016),(1, 'a', 2016, 2017),(1, 'a', 2017, 2018),(2, 'c', 2000, 2001),(2, 'c', 2001, 2002),(2, 'd', 2002, 2003),(2, 'd', 2017, 2018)


select 
    ID,
    AssocID,
    min(Start),
    max([End])
from
(
    select *,
        sum([grp_start]) over (partition by ID, AssocID order by [End]) as grp
    from
    (
        select *,
            case 
                when
                    lag([End]) over (partition by ID, AssocID order by [End]) <> [Start] 
                then 1 else 0
            end as [grp_start]
        from @T
    ) as T
)as T
group by ID, AssocID, grp
order by ID, min(Start), max([End])