我正在使用 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 | +----------+----------+---------------- -----+
在一个完美的世界中,他们设置掩护的数据库不允许他们这样做,但它是一个外部开发的数据库,不允许我们对其进行这样的更改。我们也不允许创建函数、存储过程、计数表等……</p>
查询本身应该返回每个位置有急救覆盖的分钟数,然后分解为一天中的几个小时。封面上的任何重叠都不应最终增加额外的封面,而应合并。一个人一次可以上,如果他们重叠,那么它应该只算一个人很多掩护。
示例输出:
+----------+----------+---------------- -----+------------+--------------+--------+--------+- -----+----------+ | 位置 | 来自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
抱歉这么长,但我想我会尽量给你提供尽可能多的细节。任何帮助将不胜感激。谢谢你。