【问题标题】:Creating a timeline with multiple tables in SQL Server在 SQL Server 中创建包含多个表的时间线
【发布时间】:2016-03-22 14:46:49
【问题描述】:

我有以下 3 个表:

CREATE TABLE Jedi  (
jediId INT NOT null,
name nvarchar(100) NOT NULL,
jediRank nvarchar(100) NOT NULL,
fromDate Date NOT NULL,
toDate Date NOT NULL
)

INSERT INTO Jedi(jediId, name, jediRank, fromdate, todate)
SELECT 666 jediId, 'A.Skywalker' name, 'padawan' jediRank, '1990-01-01' fromDate, '1999-12-31' toDate Union
SELECT 666 jediId, 'A.Skywalker' name, 'Jedi Knight' jediRank, '2000-01-01' fromDate, '2005-06-17' toDate Union
SELECT 666 jediId, 'A.Skywalker' name, 'Jedi Master' jediRank, '2005-06-18' fromDate, '2005-09-28' toDate Union
SELECT 666 jediId, 'D.Vader' name, 'Sith Apprentice' jediRank, '2005-09-29' fromDate, '9999-12-31' toDate  
ORDER BY jediId, fromdate, todate

CREATE TABLE lightsaberColors (
jediId int, 
lightsaberColor nvarchar(100) NOT NULL,
fromDate Date NOT NULL,
toDate Date NOT NULL
)

INSERT INTO lightsaberColors(jediId, lightsaberColor, fromdate, todate)
SELECT 666, 'blue' color, '1990-01-01' fromdate, '1992-01-01' todate UNION
SELECT 666, 'green' color, '1992-01-02' fromdate, '1992-04-15' todate UNION
SELECT 666, 'blue' color, '1992-04-16' fromdate, '2005-09-30' todate UNION
SELECT 666, 'red' color, '2005-10-01' fromdate, '9999-12-31' todate
ORDER BY fromdate, todate

CREATE TABLE mechanicalbodyparts (
jediId int, 
mechanicalBodyPart nvarchar(100) NOT NULL,
fromDate Date NOT NULL,
toDate Date NOT NULL
)
INSERT INTO mechanicalbodyparts(jediId, mechanicalBodyPart,fromDate, toDate)
SELECT 666, 'N/A' mechanicalBodyPart, '1990-01-01' fromdate, '1998-05-13' todate UNION
SELECT 666, 'hand and arm' mechanicalBodyPart, '1998-05-14' fromdate, '2005-09-29' todate UNION
SELECT 666, 'pretty much everything' mechanicalBodyPart, '2005-09-30' fromdate, '9999-12-31' todate
ORDER BY fromdate, todate

 SELECT * From jedi ORDER BY fromdate
 SELECT * From lightsaberColors ORDER BY fromdate
 SELECT * From mechanicalbodyparts ORDER BY fromdate

我想要找到的是将所有这些数据组合到一个表格中的最佳方式,该表格本质上是每个绝地的时间线。

在这种情况下我最终会得到的表格是:

CREATE TABLE JediTimeline(
jediId Int NOT null,
fromDate date NOT null,
toDate date NOT NULL,
name nvarchar(100) NOT NULL,
jediRank nvarchar(100) NOT NULL, 
mechanicalBodyPart nvarchar(100) NOT NULL,
lightsaberColor nvarchar(100) NOT NULL
)

INSERT INTO JediTimeline (jediId, fromDate, toDate, name, jediRank, mechanicalBodyPart, lightsaberColor)
Select 666, '1990-01-01', '1992-01-01', 'A.Skywalker', 'padawan', 'N/A', 'blue' Union
Select 666, '1992-01-02', '1992-04-15', 'A.Skywalker', 'padawan', 'N/A', 'green' Union
Select 666, '1992-04-16', '1998-05-13', 'A.Skywalker', 'padawan', 'N/A', 'blue' Union
Select 666, '1998-05-14', '1999-12-31', 'A.Skywalker', 'padawan', 'hand and arm', 'blue' Union
Select 666, '2000-01-01', '2005-06-17', 'A.Skywalker', 'Jedi Knight', 'hand and arm', 'blue' Union
Select 666, '2005-06-18', '2005-09-28', 'A.Skywalker', 'Jedi Master', 'hand and arm', 'blue' Union
Select 666, '2005-09-29', '2005-09-29', 'D.Vader', 'Sith Apprentice', 'hand and arm', 'blue' Union
Select 666, '2005-09-30', '2005-09-30', 'D.Vader', 'Sith Apprentice', 'pretty much everything', 'blue' Union
Select 666, '2005-10-01', '9999-12-31', 'D.Vader', 'Sith Apprentice', 'pretty much everything', 'red'  
ORDER BY 1,2,3


SELECT *
FROM JediTimeline

现在,我为此提出了一个解决方案,但它使用的游标在这种情况下可以正常工作,但当我使用的数据明显更大时,它并不理想。

我正在使用 SQL Server 2012。

顺便说一句,这是“岛屿”问题的一个例子吗?

【问题讨论】:

  • 可能有点矫枉过正,但这听起来很适合 SQL Server Analysis Services (OLAP)
  • 是的,这是另一个差距和孤岛问题的一个很好的例子。然而,你的覆盖在几个间隙和岛屿上。无论如何,您应该将标签添加到您的问题中:gaps-and-islands
  • @JohnHartsock - 你会如何在 SSAS 中做到这一点?我想我目前更喜欢 T-SQL 解决方案,但我会对你在 SSAS 中如何做到这一点感兴趣。
  • Inga,如果您对我的解决方案有任何疑问,请告诉我,也许有办法满足您的需求。
  • @madsNielsen 没问题。谢谢。我只是想看看约翰在说什么。

标签: sql sql-server timeline temporal-database


【解决方案1】:

如果您运行 >=< 方案,而不是 >=<=(在 fromDate 和 toDate 上),则可以避免所有 DATEADDs。

with
    UniqueCutoffDates as (
        select distinct fromDate as cutoff, jediId from Jedi union
        select distinct fromDate,           jediId from lightsaberColors union
        select distinct fromDate,           jediId from mechanicalbodyparts union

        select distinct DATEADD(d,1,toDate), jediId from Jedi                where toDate <> '9999-12-31' union
        select distinct DATEADD(d,1,toDate), jediId from lightsaberColors    where toDate <> '9999-12-31' union
        select distinct DATEADD(d,1,toDate), jediId from mechanicalbodyparts where toDate <> '9999-12-31'
    )

select
    jedi.jediId,
    dates.cutoff as fromDate,
    DATEADD(d,-1,LEAD(dates.cutoff,1,'9999-12-31') OVER (partition by jedi.jediId order by dates.cutoff)) as toDate,
    jedi.name,
    jedi.jediRank,
    body.mechanicalBodyPart,
    colors.lightsaberColor
from
    UniqueCutoffDates dates
    inner join Jedi on
        jedi.fromDate <= dates.cutoff and
        Jedi.toDate > DATEADD(d,-1,dates.cutoff) and
        jedi.jediId = dates.jediId
    inner join lightsaberColors colors on
        colors.fromDate <= dates.cutoff and
        colors.toDate > DATEADD(d,-1,dates.cutoff) and
        colors.jediId = jedi.jediId
    inner join mechanicalbodyparts body on
        body.fromDate <= dates.cutoff and
        body.toDate > DATEADD(d,-1,dates.cutoff) and
        body.jediId = jedi.jediId

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    相关资源
    最近更新 更多