我在SQLServer 2008 R2上
我试图为给定期间(通常为30-90天)制造资源的活动创建报告和图表
根据运行时间(例如4天)创建作业。如果周末没有工作并且上述工作在星期五开始,那么资源的活动需要显示1天运行,2天停止,3天运行,而生产调度程序不必进行两项工作。我有工作'一个表中的计划和另一个表中的停机时间(因此将DT视为某种日历表)。不同寻常的是,结束时间由停机因素提供。
所以我需要查询为这个作业创建3个日期时间范围:Fri跑步,周六,太阳下山,周一,周二,周三跑步。注意:单个作业可能有多个停机事件。
已经围绕这个圈了一会儿。我确信这是一种优雅的方式:我无法找到它。我发现了几个类似的帖子,但不能适用于我的案例(或至少可以让他们工作)
以下是一些示例日期和预期结果。我希望解释和示例数据是清楚的。
-- Create tables to work with / Source and Destination
CREATE TABLE #Jobs
(
ResourceID int
,JobNo VARCHAR(10)
,startdate SMALLDATETIME
,enddate SMALLDATETIME
)
CREATE TABLE #Downtime
(
ResourceID INT
,Reason VARCHAR(10)
,startdate SMALLDATETIME
,enddate SMALLDATETIME
)
CREATE TABLE #Results
(
ResourceID INT
,Activity VARCHAR(10)
,startdate SMALLDATETIME
,enddate SMALLDATETIME
,ActivityType varchar(1)
)
-- Job Schedule
INSERT INTO [#Jobs]
(
[ResourceID],
[JobNo],
startdate
,enddate
)
SELECT 1, 'J1', '2014-04-01 08:00' ,'2014-04-01 17:00'
UNION ALL
SELECT 1, 'J2', '2014-04-01 17:00' , '2014-04-01 23:00'
UNION ALL
SELECT 2, 'J3', '2014-04-01 08:00' ,'2014-04-01 23:00'
UNION ALL
SELECT 3, 'J4', '2014-04-01 08:00' ,'2014-04-01 09:00'
SELECT * FROM #jobs
-- Downtime Scehdule
INSERT INTO [#Downtime]
(
[ResourceID],
Reason,
startdate
,enddate
)
SELECT 1, 'DOWN', '2014-04-01 10:00' ,'2014-04-01 11:00'
UNION ALL
SELECT 1, 'DOWN', '2014-04-01 21:00' , '2014-04-01 22:00'
UNION ALL
SELECT 2, 'DOWN', '2014-04-01 10:00' ,'2014-04-01 11:00'
UNION ALL
SELECT 2, 'DOWN', '2014-04-01 21:00' , '2014-04-01 22:00'
UNION ALL
SELECT 3, 'DOWN', '2014-04-01 10:00' ,'2014-04-01 11:00'
UNION ALL
SELECT 3, 'DOWN', '2014-04-01 21:00' , '2014-04-01 22:00'
SELECT * FROM #Downtime
-- Expected Results
INSERT INTO [#Results]
(
Activity,
[ResourceID],
startdate
,enddate
,[ActivityType]
)
SELECT 'J1', 1, '2014-04-01 08:00' ,'2014-04-01 10:00', 'P'
UNION ALL
SELECT 'DOWN', 1, '2014-04-01 10:00' , '2014-04-01 11:00', 'D'
UNION ALL
SELECT 'J1', 1, '2014-04-01 11:00' ,'2014-04-01 17:00', 'P'
UNION ALL
SELECT 'J2', 1, '2014-04-01 17:00' , '2014-04-01 21:00', 'P'
UNION ALL
SELECT 'DOWN', 1, '2014-04-01 21:00' , '2014-04-01 22:00', 'D'
UNION ALL
SELECT 'J2', 1, '2014-04-01 22:00' ,'2014-04-01 23:00', 'P'
UNION ALL
SELECT 'J3', 2, '2014-04-01 08:00' ,'2014-04-01 10:00', 'P'
UNION ALL
SELECT 'DOWN', 2, '2014-04-01 10:00' , '2014-04-01 11:00', 'D'
UNION ALL
SELECT 'J3', 2, '2014-04-01 11:00' ,'2014-04-01 21:00', 'P'
UNION ALL
SELECT 'DOWN', 2, '2014-04-01 21:00' , '2014-04-01 22:00', 'D'
UNION ALL
SELECT 'J3', 2, '2014-04-01 22:00' ,'2014-04-01 23:00', 'P'
UNION ALL
SELECT 'J4', 3, '2014-04-01 08:00' ,'2014-04-01 09:00', 'P'
UNION ALL
SELECT 'DOWN', 3, '2014-04-01 10:00' , '2014-04-01 11:00', 'D'
UNION ALL
SELECT 'DOWN', 3, '2014-04-01 21:00' , '2014-04-01 22:00', 'D'
SELECT * FROM #Results
ORDER BY [ResourceID], Startdate
DELETE FROM #Results
|--------------------------J1------------------------------------| running |----D1-----| |-------D2-------| down |--J1--|----D1-----|-------J1------|-------D2-------|-----J1-----| result
|-----------------------------J1-----------| running |----D1-------| down |-----------------J1-----------------------| |----D1-------| result
有人能指出我正确的方向吗?
这是我最接近的。当存在重叠时工作得很好,但是在J4工作在停机之前结束时失败
WITH cte
AS ( SELECT
ROW_NUMBER() OVER ( ORDER BY ResourceID, dt ) AS Rno
,x.ResourceID
,x.Activity
,Dt
,xdt.ActivityType
FROM
(
SELECT
ResourceID
,JobNo AS Activity
,startdate
,enddate
,'P' AS ActivityType
FROM #Jobs
UNION ALL
SELECT
ResourceID
,Reason AS Activity
,startdate
,enddate
,'D' AS ActivityType
FROM #Downtime
) AS x
CROSS APPLY
(
VALUES ( x.startdate, x.ActivityType),
( x.enddate, x.ActivityType) ) AS xdt
( Dt, ActivityType )
)
SELECT
x.ResourceID
,CASE WHEN x.Activity > x1.Activity THEN x.Activity
ELSE x1.Activity
END AS Activity
,x.dt AS StartDate
,x1.Dt AS EndDate
,CASE WHEN x.ActivityType > x1.ActivityType THEN x.ActivityType
ELSE x1.ActivityType
END AS activitytype
FROM
cte AS x
LEFT OUTER JOIN cte AS x1 ON x.ResourceID = x1.ResourceID
AND x.Rno = x1.Rno - 1
WHERE
x1.Dt IS NOT NULL
AND x1.Dt <> x.Dt;
由于
标记
答案 0 :(得分:1)
你实际上非常接近 - 而不是在初始CTE中做所有事情,你实际上想要稍后再加入原始数据。基本上,您正在执行变体on the answer supplied here 以下查询可以满足您的需求:
WITH AllDates AS (SELECT a.*, ROW_NUMBER() OVER(PARTITION BY resourceId ORDER BY rangeDate) AS rn
FROM (SELECT resourceId, startDate
FROM Jobs
UNION ALL
SELECT resourceId, endDate
FROM Jobs
UNION ALL
SELECT resourceId, startDate
FROM Downtime
UNION ALL
SELECT resourceId, endDate
FROM DownTime) a(resourceId, rangeDate)),
Range AS (SELECT startRange.resourceId,
startRange.rangeDate AS startDate, endRange.rangeDate AS endDate
FROM AllDates startRange
JOIN AllDates endRange
ON endRange.resourceId = startRange.resourceId
AND endRange.rn = startRange.rn + 1
AND endRange.rangeDate <> startRange.rangeDate)
SELECT Range.resourceId, Range.startDate, Range.endDate,
COALESCE(Downtime.reason, Jobs.jobNo) as activity
FROM Range
LEFT JOIN Jobs
ON Jobs.resourceId = Range.resourceId
AND Jobs.startDate <= Range.startDate
AND Jobs.endDate >= Range.endDate
LEFT JOIN Downtime
ON Downtime.resourceId = Range.resourceId
AND Downtime.startDate <= Range.startDate
AND Downtime.endDate >= Range.endDate
WHERE Jobs.jobNo IS NOT NULL
OR Downtime.reason IS NOT NULL
(和working fiddle。这实际上应该是ANSI标准的SQL) ......产生了预期的结果:
RESOURCEID STARTDATE ENDDATE ACTIVITY
----------------------------------------------------------------------------
1 2014-04-01 08:00:00 2014-04-01 10:00:00 J1
1 2014-04-01 10:00:00 2014-04-01 11:00:00 DOWN
1 2014-04-01 11:00:00 2014-04-01 17:00:00 J1
1 2014-04-01 17:00:00 2014-04-01 21:00:00 J2
1 2014-04-01 21:00:00 2014-04-01 22:00:00 DOWN
1 2014-04-01 22:00:00 2014-04-01 23:00:00 J2
2 2014-04-01 08:00:00 2014-04-01 10:00:00 J3
2 2014-04-01 10:00:00 2014-04-01 11:00:00 DOWN
2 2014-04-01 11:00:00 2014-04-01 21:00:00 J3
2 2014-04-01 21:00:00 2014-04-01 22:00:00 DOWN
2 2014-04-01 22:00:00 2014-04-01 23:00:00 J3
3 2014-04-01 08:00:00 2014-04-01 09:00:00 J4
3 2014-04-01 10:00:00 2014-04-01 11:00:00 DOWN
3 2014-04-01 21:00:00 2014-04-01 22:00:00 DOWN