在 SQL 服务器中创建包含多个表的时间线
Creating a timeline with multiple tables in SQL Server
我有以下 3 个 table:
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
我试图找到的是将所有这些数据组合成一个 table 的最佳方式,这基本上是每个绝地武士的时间线。
在这种情况下我会得到的 table 是:
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。
附带说明一下,这是 'Islands' 问题的一个例子吗?
如果您 运行 使用 >=
和 <
方案而不是 >=
和 <=
,则可以避免所有 DATEADD
(关于 fromDate 和 toDate)。
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
我有以下 3 个 table:
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
我试图找到的是将所有这些数据组合成一个 table 的最佳方式,这基本上是每个绝地武士的时间线。
在这种情况下我会得到的 table 是:
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。
附带说明一下,这是 'Islands' 问题的一个例子吗?
如果您 运行 使用 >=
和 <
方案而不是 >=
和 <=
,则可以避免所有 DATEADD
(关于 fromDate 和 toDate)。
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