SQL和时态数据
给出一张预约表,如下所示:SQL和时态数据,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,给出一张预约表,如下所示: User Start End UserA 2016-01-15 12:00:00 2016-01-15 14:00:00 UserA 2016-01-15 15:00:00 2016-01-15 17:00:00 UserB 2016-01-15 13:00:00 2016-01-15 15:00:00 UserB 2016-01-15 13:3
User Start End
UserA 2016-01-15 12:00:00 2016-01-15 14:00:00
UserA 2016-01-15 15:00:00 2016-01-15 17:00:00
UserB 2016-01-15 13:00:00 2016-01-15 15:00:00
UserB 2016-01-15 13:32:00 2016-01-15 15:00:00
UserB 2016-01-15 15:30:00 2016-01-15 15:30:00
UserB 2016-01-15 15:45:00 2016-01-15 16:00:00
UserB 2016-01-15 17:30:00 2016-01-15 18:00:00
我想创建一个不同时间间隔的列表,其中相同数量的人有约会:
Start End Count
2016-01-15 12:00:00 2016-01-15 13:00:00 1
2016-01-15 13:00:00 2016-01-15 14:00:00 2
2016-01-15 14:00:00 2016-01-15 15:45:00 1
2016-01-15 15:45:00 2016-01-15 16:00:00 2
2016-01-15 16:00:00 2016-01-15 17:00:00 1
2016-01-15 17:00:00 2016-01-15 17:30:00 0
2016-01-15 17:30:00 2016-01-15 18:00:00 1
在SQL(最好是SQL Server 2008)中,我将如何做到这一点
编辑:澄清:手动,通过为每个用户制作一行,标记阻止时间,然后汇总具有标记的行数,获得结果:
Time 12 13 14 15 16 17
UserA xxxxxxxx xxxxxxxx
UserB xxxxxxxx x xx
Count 1 2 1 21 0 1
结果集将在可用的最短时间开始,在可用的最长时间结束,虽然ASCII art只有15分钟的分辨率,但我至少需要一分钟的分辨率。如果这对您来说比较容易的话,我想您可以在结果中保留带0的行。一定有比这更简单的方法,但至少您可以单独执行每个步骤:
declare @t table ([User] varchar(19) not null,Start datetime2 not null,[End] datetime2 not null)
insert into @t([User], Start, [End]) values
('UserA','2016-01-15T12:00:00','2016-01-15T14:00:00'),
('UserA','2016-01-15T15:00:00','2016-01-15T17:00:00'),
('UserB','2016-01-15T13:00:00','2016-01-15T15:00:00'),
('UserB','2016-01-15T13:32:00','2016-01-15T15:00:00'),
('UserB','2016-01-15T15:30:00','2016-01-15T15:30:00'),
('UserB','2016-01-15T15:45:00','2016-01-15T16:00:00'),
('UserB','2016-01-15T17:30:00','2016-01-15T18:00:00')
;With Times as (
select Start as Point from @t
union
select [End] from @t
), Ordered as (
select Point,ROW_NUMBER() OVER (ORDER BY Point) as rn
from Times
), Periods as (
select
o1.Point as Start,
o2.Point as [End]
from
Ordered o1
inner join
Ordered o2
on
o1.rn = o2.rn - 1
), UserCounts as (
select p.Start,p.[End],COUNT(distinct [User]) as Cnt,ROW_NUMBER() OVER (Order BY p.[Start]) as rn
from
Periods p
left join
@t t
on
p.Start < t.[End] and
t.Start < p.[End]
group by
p.Start,p.[End]
), Consolidated as (
select uc.*
from
UserCounts uc
left join
UserCounts uc_anti
on
uc.rn = uc_anti.rn + 1 and
uc.Cnt = uc_anti.Cnt
where
uc_anti.Cnt is null
union all
select c.Start,uc.[End],c.Cnt,uc.rn
from
Consolidated c
inner join
UserCounts uc
on
c.Cnt = uc.Cnt and
c.[End] = uc.Start
)
select
Start,MAX([End]) as [End],Cnt
from
Consolidated
group by
Start,Cnt
order by Start
我甚至得到了零行,我不确定我是否能够变戏法为现实一定有比这更简单的方法,但至少你可以单独遵循每一步:
declare @t table ([User] varchar(19) not null,Start datetime2 not null,[End] datetime2 not null)
insert into @t([User], Start, [End]) values
('UserA','2016-01-15T12:00:00','2016-01-15T14:00:00'),
('UserA','2016-01-15T15:00:00','2016-01-15T17:00:00'),
('UserB','2016-01-15T13:00:00','2016-01-15T15:00:00'),
('UserB','2016-01-15T13:32:00','2016-01-15T15:00:00'),
('UserB','2016-01-15T15:30:00','2016-01-15T15:30:00'),
('UserB','2016-01-15T15:45:00','2016-01-15T16:00:00'),
('UserB','2016-01-15T17:30:00','2016-01-15T18:00:00')
;With Times as (
select Start as Point from @t
union
select [End] from @t
), Ordered as (
select Point,ROW_NUMBER() OVER (ORDER BY Point) as rn
from Times
), Periods as (
select
o1.Point as Start,
o2.Point as [End]
from
Ordered o1
inner join
Ordered o2
on
o1.rn = o2.rn - 1
), UserCounts as (
select p.Start,p.[End],COUNT(distinct [User]) as Cnt,ROW_NUMBER() OVER (Order BY p.[Start]) as rn
from
Periods p
left join
@t t
on
p.Start < t.[End] and
t.Start < p.[End]
group by
p.Start,p.[End]
), Consolidated as (
select uc.*
from
UserCounts uc
left join
UserCounts uc_anti
on
uc.rn = uc_anti.rn + 1 and
uc.Cnt = uc_anti.Cnt
where
uc_anti.Cnt is null
union all
select c.Start,uc.[End],c.Cnt,uc.rn
from
Consolidated c
inner join
UserCounts uc
on
c.Cnt = uc.Cnt and
c.[End] = uc.Start
)
select
Start,MAX([End]) as [End],Cnt
from
Consolidated
group by
Start,Cnt
order by Start
我甚至得到了一个零行,我不确定我是否能够变出它的存在如果你有一个表,这种查询更容易编写。但在这个例子中,我用一个。CTE返回约会块,然后我们可以将其加入约会数据。我无法确定示例数据中的间隔模式,因此我以一小时为单位显示了结果。您可以修改此部分,或者在第二个表中定义自己的部分 样本数据 我使用了两个变量来限制返回的结果,使其仅限于那些在给定起点和终点内的约会
/* Set an start and end point for the next query
*/
DECLARE @Start DATETIME = '2016-01-15 12:00:00';
DECLARE @End DATETIME = '2016-01-15 18:00:00';
WITH Calendar AS
(
/* Anchor returns start of first appointment
*/
SELECT
@Start AS [Start],
DATEADD(SECOND, -1, DATEADD(HOUR, 1, @Start)) AS [End]
UNION ALL
/* Recursion, keep adding new records until end of last appointment
*/
SELECT
DATEADD(HOUR, 1, [Start]) AS [Start],
DATEADD(HOUR, 1, [End]) AS [End]
FROM
Calendar
WHERE
[End] <= @End
)
SELECT
c [Start],
c [End],
COUNT(DISTINCT s [User]) AS [Count]
FROM
Calendar AS c
LEFT OUTER JOIN @Sample AS s ON s [Start] BETWEEN c [Start] AND c [End]
OR s [End] BETWEEN c [Start] AND c [End]
GROUP BY
c [Start],
c [End]
;
因为约会可以超过一个小时,所以可能会导致多行。这就解释了为什么7个样本行总共返回9个。如果您有一个表,这种查询更容易编写。但在这个例子中,我用一个。CTE返回约会块,然后我们可以将其加入约会数据。我无法确定示例数据中的间隔模式,因此我以一小时为单位显示了结果。您可以修改此部分,或者在第二个表中定义自己的部分 样本数据 我使用了两个变量来限制返回的结果,使其仅限于那些在给定起点和终点内的约会
/* Set an start and end point for the next query
*/
DECLARE @Start DATETIME = '2016-01-15 12:00:00';
DECLARE @End DATETIME = '2016-01-15 18:00:00';
WITH Calendar AS
(
/* Anchor returns start of first appointment
*/
SELECT
@Start AS [Start],
DATEADD(SECOND, -1, DATEADD(HOUR, 1, @Start)) AS [End]
UNION ALL
/* Recursion, keep adding new records until end of last appointment
*/
SELECT
DATEADD(HOUR, 1, [Start]) AS [Start],
DATEADD(HOUR, 1, [End]) AS [End]
FROM
Calendar
WHERE
[End] <= @End
)
SELECT
c [Start],
c [End],
COUNT(DISTINCT s [User]) AS [Count]
FROM
Calendar AS c
LEFT OUTER JOIN @Sample AS s ON s [Start] BETWEEN c [Start] AND c [End]
OR s [End] BETWEEN c [Start] AND c [End]
GROUP BY
c [Start],
c [End]
;
因为约会可以超过一个小时,所以可能会导致多行。这就解释了为什么7个样本行总共返回9个。您真的需要0行吗?基于零源行将行变为存在可能很棘手。在所需的结果集中,从哪里获得开始和结束时间?它们与您的数据不匹配,也不遵循模式。@DevlEnvonate-我认为具有相同用户数的相邻时段被合并,而且用户的约会似乎彼此重叠。您真的需要0行吗?基于零源行将行变为存在可能很棘手。在所需的结果集中,从哪里获得开始和结束时间?它们与您的数据不匹配,也不遵循模式。@DevlEnformnate-我认为具有相同用户数的相邻时段是合并的,而且用户的约会似乎彼此重叠。