【发布时间】:2015-10-30 17:09:35
【问题描述】:
我正在使用 SQL Server Management Studio 2008 创建查询。用于创建报告的 Reporting Services 2008。
几周以来,我一直在努力解决这个问题,但我遇到了障碍。我希望有人能够提出解决方案,因为现在我的大脑已经变成糊状了。
我目前正在开发一个 SQL 查询,它将向 Reporting Services 报告提供数据。该报告的目的是显示我们所在县周边地区急救提供者的可用百分比。我们的想法是,在我们的 20 个地点中的每一个,一次都应该只有一名急救人员提供掩护。
这一切都很好,除了一个位置的急救人员在每个掩护期的开始和结束时重叠了他们的掩护。
封面重叠示例:
|位置 |开始日期 |结束日期 | +----------+----------+---------------- -----+ |灯芯 | 22/06/2015 09:00:00 | 22/06/2015 19:00:00 | |灯芯 | 22/06/2015 18:30:00 | 23/06/2015 09:00:00 | |灯芯 | 23/06/2015 09:00:00 | 23/06/2015 18:30:00 | |灯芯 | 23/06/2015 18:00:00 | 24/06/2015 09:00:00 | +----------+----------+---------------- -----+在一个完美的世界中,他们设置掩护的数据库不允许他们这样做,但它是一个外部开发的数据库,不允许我们对其进行类似的更改。我们也不允许创建函数、存储过程、计数表等......
查询本身应返回每个地点有急救覆盖的分钟数,然后分解为一天中的小时数。封面上的任何重叠都不应最终增加额外的封面,而应合并。一次可以一个人,如果他们重叠,那么它应该只算一个人很多掩护。
示例输出:
+----------+----------+---------------- -----+------------+--------------+--------+--------+- -----+----------+ |位置 |来自Dt |到Dt |时差 |可用性 |第N天 |天号 |小时 |天数 | +----------+----------+---------------- -----+------------+--------------+--------+--------+- -----+----------+ |灯芯 | 22/06/2015 18:00:00 | 22/06/2015 18:59:59 | 59 | 100 |星期一 | 1 | 18 | 0 | |灯芯 | 22/06/2015 18:30:00 | 22/06/2015 18:59:59 | 29 | 50 |星期一 | 1 | 18 | 0 | |灯芯 | 22/06/2015 19:00:00 | 22/06/2015 19:59:59 | 59 | 100 |星期一 | 1 | 19 | 0 | +----------+----------+---------------- -----+------------+--------------+--------+--------+- -----+----------+示例代码:
DECLARE
@StartTime datetime,
@EndTime datetime,
@GivenDate datetime;
SET @GivenDate = '2015-06-22';
SET @StartTime = @GivenDate + ' 00:00:00';
SET @EndTime = '2015-06-23' + ' 23:59:59';
Declare @Sample Table
(
Location Varchar(50),
StartDate Datetime,
EndDate Datetime
)
Insert @Sample
Select
sta.location,
act.Start,
act.END
from emp,
con,
sta,
act
where
emp.ID = con.ID
and con.location = sta.location
and SUBSTRING(sta.ident,3,2) in ('51','22')
and convert(varchar(10),act.start,111) between @GivenDate and @EndTime
and act.ACT= 18
group by sta.location,
act.Start,
act.END
order by 2
;WITH Yak (location, fromDt, toDt, maxDt,hourdiff)
AS (
SELECT location,
StartDate,
/*check if the period of cover rolls onto the next hour */
convert(datetime,convert(varchar(21),
CONVERT(varchar(10),StartDate,111)+' '
+convert(varchar(2),datepart(hour,StartDate))+':59'+':59'))
,
EndDate
,dateadd(hour,1,dateadd(hour, datediff(hour, 0, StartDate), 0))-StartDate
FROM @Sample
UNION ALL
SELECT location,
dateadd(second,1,toDt),
dateadd(hour, 1, toDt),
maxDt,
hourdiff
FROM Yak
WHERE toDt < maxDt
) ,
TAB1 (location, FROMDATE,TODATE1,TODATE) AS
(SELECT
location,
@StartTime,
convert(datetime,convert(varchar(21),
CONVERT(varchar(10),@StartTime,120)+' '
+convert(varchar(2),datepart(hour,@StartTime))+':59'+':59.999')),
@EndTime
from @Sample
UNION ALL
SELECT
location,
(DATEADD(hour, 1,(convert(datetime,convert(varchar(21),
CONVERT(varchar(10),FROMDATE,120)+' '
+convert(varchar(2),datepart(hour,FROMDATE))+':00'+':00.000')))))ToDate,
(DATEADD(hour, 1,(convert(datetime,convert(varchar(21),
CONVERT(varchar(10),TODATE1,120)+' '
+convert(varchar(2),datepart(hour,TODATE1))+':59'+':59.999'))))) Todate1,
TODATE
FROM TAB1 WHERE TODATE1 < TODATE
),
/*CTE Tab2 adds zero values to all possible hours between start and end dates */
TAB2 AS
(SELECT location, FROMDATE,
CASE WHEN TODATE1 > TODATE THEN TODATE ELSE TODATE1 END AS TODATE
FROM TAB1)
SELECT location,
fromDt,
/* Display MaxDT as start time if cover period goes into next dat */
CASE WHEN toDt > maxDt THEN maxDt ELSE toDt END AS toDt,
/* If the end date is on the next day find out the minutes between the start date and the end of the day or find out the minutes between the next day and the end date */
Case When ToDt > Maxdt then datediff(mi,fromDt,maxDt) else datediff(mi,FromDt,ToDt) end as TimeDiff,
Case When ToDt > Maxdt then round(datediff(S,fromDt,maxDt)/3600.0*100,0) else round(datediff(S,FromDt,ToDt)/3600.0*100.0,0) end as Availability,
/*Display the name of the day of the week*/
CASE WHEN toDt > maxDt THEN datename(dw,maxDt) ELSE datename(dw,fromDt) END AS DayN,
CASE WHEN toDt > maxDt THEN case when datepart(dw,maxDt)-1 = 0 then 7 else datepart(dw,maxDt)-1 end ELSE case when datepart(dw,fromDt)-1 = 0 then 7 else datepart(dw,fromDt)-1 END end AS DayNo
,DATEPART(hour, fromDt) as Hour,
'0' as DayCount
FROM Yak
where Case When ToDt > Maxdt then datediff(mi,fromDt,maxDt) else datediff(mi,FromDt,ToDt) end <> 0
group by location,fromDt,maxDt,toDt
Union all
SELECT
tab2.location,
convert(varchar(19),Tab2.FROMDATE,120),
convert(varchar(19),Tab2.TODATE,120),
'0',
'0',
datename(dw,FromDate) DayN,
case when datepart(dw,FromDate)-1 = 0 then 7 else datepart(dw,FromDate)-1 end AS DayNo,
DATEPART(hour, fromDate) as Hour,
COUNT(distinct datename(dw,fromDate))
FROM TAB2
Where datediff(MINUTE,convert(varchar(19),Tab2.FROMDATE,120),convert(varchar(19),Tab2.TODATE,120)) > 0
group by location, TODATE, FROMDATE
Order by 2
option (maxrecursion 0)
我尝试了以下论坛条目,但它们在我的情况下不起作用: http://forums.teradata.com/forum/general/need-help-merging-consecutive-and-overlapping-date-spans
Checking for time range overlap, the watchman problem [SQL]
Calculate Actual Downtime ignoring overlap in dates/times
很抱歉这么长,但我想我会尽力为您提供尽可能详细的信息。任何帮助将不胜感激。谢谢。
【问题讨论】:
-
您的示例输出没有多大意义,它充满了重叠。我的想法是消除重叠。
-
如果结束时间与开始时间重叠,是否可以忽略结束时间?
-
Bulat - 这是当前数据的输出。目前我还没有找到消除重叠的方法。
-
MolleyC - 目前我不知道如何运行测试以找到重叠。理想情况下,如果发现时间重叠,则采用最早的开始日期和最晚的结束日期。
标签: sql sql-server reporting-services overlap availability