SQL Server 2012.我需要创建一个查询来确定哪些作业在过去的任何给定日期处于哪种状态(BONUS:他们处于该状态的时间长度。)
我有一个Job Status Log表,其中包含以下列和结构:
JobStatusNo JobNo Status Rem Entered EnteredBy
-------------------------------------------------------------------------
1644897 420969 801 Reschedule 2017-09-20 17:58:18.503 1488
1644896 420969 812 Cancelled 2017-09-15 08:20:48.390 1267
1644895 420969 803 Confirmed 2017-09-14 10:13:25.733 1231
1644894 420969 802 Call Bob 2017-09-14 09:35:57.337 1231
1644893 420969 801 2017-09-08 18:18:16.490 1488
1644892 420965 807 2017-09-20 17:55:02.660 1488
1644891 420965 809 2017-09-20 17:47:52.340 1488
1644890 420965 806 2017-09-20 17:40:22.580 1488
1644889 420965 803 Confirmed 2017-09-20 17:05:30.870 1193
1644888 420965 801 2017-09-20 17:05:29.130 1193
1644877 420964 801 2017-09-20 17:02:16.830 1193
我想我希望有一个特定的工作号码,然后是每个状态,以及何时(另外我不关心评论或谁进入工作):
JobNo 1Status 1Entered 2Status 2Entered
--------------------------------------------------------------
420969 801 2017-09-20 17:58:18.503 812 2017-09-15.337
420968 801 2017-09-20 17:55:02.660
420967 801 2017-09-20 17:47:52.340
420966 801 2017-09-20 17:40:22.580
420965 803 2017-09-20 17:05:30.870
420965 801 2017-09-20 17:05:29.130
420964 801 2017-09-20 17:02:16.830
...在指示3Status和3Entered之后有更多列。我只需要编码8个状态/输入日期,因为这是作业重新排序或替换状态的最多次数。如果最终有更多列,我将能够扩展我在这里的任何答案以包含该逻辑。
...因为我最终的答案"将于2016年7月1日(任何指定日期):87个职位处于801状态,255个职位处于806状态,5个职位处于809状态。事实上,我需要做数学来确定最终每个工作的特定状态如何,但这是我的第一个问题而且我不知道我的答案会有多复杂,我称之为在这里,我猜测一旦我通过DateDiff获得这些状态和日期,我就可以弄明白其余部分。
我已经尝试过从UNPIVOT,Lag / Lead,分组,MAX等等我能想到的所有组合,并且无处可去。
在这一点上,我甚至可能会错过一些简单的东西,并且会对答案感到非常愚蠢,但我很好并且真的被困住了。我是否正在尝试从他们目前所在的行中获取这些列?有没有办法采取给定的日期并按原样使用表?如果有什么不清楚,我会尝试澄清更新或答案。干杯!
以下是我从@Fercstar中选择的答案:
WITH A
AS
(
SELECT
*
,ROW_NUMBER() OVER(PARTITION BY JobNo ORDER BY Entered DESC) as StatusOrder
FROM MyJobStatusTable
)
SELECT
A.JobNo
,A.Status as Status1
,A.Entered as Entered1
,A2.Status as Status2
,A2.Entered as Entered2
,A3.Status as Status3
,A3.Entered as Entered3
,A4.Status as Status4
,A4.Entered as Entered4
,A5.Status as Status5
,A5.Entered as Entered5
,A6.Status as Status6
,A6.Entered as Entered6
,A7.Status as Status7
,A7.Entered as Entered7
,A8.Status as Status8
,A8.Entered as Entered8
,A9.Status as Status9
,A9.Entered as Entered9
FROM A
LEFT JOIN A as A2
ON A2.JobNo = A.JobNo
AND A2.StatusOrder = 2
LEFT JOIN A as A3
ON A3.JobNo = A.JobNo
AND A3.StatusOrder = 3
LEFT JOIN A as A4
ON A4.JobNo = A.JobNo
AND A4.StatusOrder = 4
LEFT JOIN A as A5
ON A5.JobNo = A.JobNo
AND A5.StatusOrder = 5
LEFT JOIN A as A6
ON A6.JobNo = A.JobNo
AND A6.StatusOrder = 6
LEFT JOIN A as A7
ON A7.JobNo = A.JobNo
AND A7.StatusOrder = 7
LEFT JOIN A as A8
ON A8.JobNo = A.JobNo
AND A8.StatusOrder = 8
LEFT JOIN A as A9
ON A9.JobNo = A.JobNo
AND A9.StatusOrder = 9
WHERE A.StatusOrder = 1
在超过一百万行数据的情况下在12秒内运行,无需临时表管理。优雅!谢谢@Fercstar。
答案 0 :(得分:0)
如果您的状态数量有限,则可以使用
DECLARE @table table (JobStatusNo int , JobNo int, Status int, Rem varchar(25) , Entered datetime, EnteredBy int )
Insert @table (JobStatusNo ,JobNo ,Status ,Rem ,Entered ,EnteredBy) values
(1644897 ,420969 ,801 ,'Reschedule' ,'2017-09-20 17:58:18.503', 1488)
,(1644896 ,420969 ,812 ,'Cancelled' ,'2017-09-15 08:20:48.390', 1267)
,(1644895 ,420969 ,803 ,'Confirmed' ,'2017-09-14 10:13:25.733', 1231)
,(1644894 ,420969 ,802 ,'Call Bob ' ,'2017-09-14 09:35:57.337', 1231)
,(1644893 ,420969 ,801 ,' ' ,'2017-09-08 18:18:16.490', 1488)
,(1644892 ,420968 ,801 ,' ' ,'2017-09-20 17:55:02.660', 1488)
,(1644891 ,420967 ,801 ,' ' ,'2017-09-20 17:47:52.340', 1488)
,(1644890 ,420966 ,801 ,' ' ,'2017-09-20 17:40:22.580', 1488)
,(1644880 ,420965 ,803 ,'Confirmed' ,'2017-09-20 17:05:30.870', 1193)
,(1644879 ,420965 ,801 ,' ' ,'2017-09-20 17:05:29.130', 1193)
,(1644877 ,420964 ,801 ,' ' ,'2017-09-20 17:02:16.830', 1193)
;With CTE as (
SELECT T.JobNo
,CASE WHEN Substring(CAST ( T.Status as char(3)),2,1) = '0' THEN T.Status ELSE NULL END [1Status]
,CASE WHEN Substring(CAST ( T.Status as char(3)),2,1) = '0' THEN T.Entered ELSE NULL END [1Entered]
,CASE WHEN Substring(CAST ( C.Status as char(3)),2,1) = '1' THEN C.Status ELSE NULL END [2Status]
,CASE WHEN Substring(CAST ( C.Status as char(3)),2,1) = '1' THEN C.Entered ELSE NULL END [2Entered]
from @table t Cross apply (Values(Status , Entered)) C (Status,Entered)
)
SELECT
JobNo
,MIN([1Status]) [1Status ]
,MIN([1Entered]) [1Entered]
,MAX([2Status ]) [2Status ]
,MAX([2Entered]) [2Entered]
,Convert(char(8), dateadd(MINUTE, DATEDIFF(Minute,MIN([1Entered]),MAX([2Entered])), ''), 114) StatusTime
FROm Cte
Group By
JobNo
结果
JobNo 1Status 1Entered 2Status 2Entered StatusTime
----------- ----------- ----------------------- ----------- ----------------------- ---------------
420964 801 2017-09-20 17:02:16.830 NULL NULL NULL
420965 801 2017-09-20 17:05:29.130 NULL NULL NULL
420966 801 2017-09-20 17:40:22.580 NULL NULL NULL
420967 801 2017-09-20 17:47:52.340 NULL NULL NULL
420968 801 2017-09-20 17:55:02.660 NULL NULL NULL
420969 801 2017-09-08 18:18:16.490 812 2017-09-15 08:20:48.390 14:02:00
答案 1 :(得分:0)
您可以使用
ROW_NUMBER() OVER(PARTITION BY JobNo ORDER BY Entered DESC)
这将获得作业的状态顺序,其中1是最新的。 然后你可以按此转动。
编辑 - 基于样本数据的完整查询
With A
As
(
Select *, ROW_NUMBER() OVER(PARTITION BY JobNo ORDER BY Entered DESC) as StatusOrder From #Table
)
Select
A.JobNo
,A.Status as Status1
,A.Entered as Entered1
,A2.Status as Status2
,A2.Entered as Entered2
,A3.Status as Status3
,A3.Entered as Entered3
,A4.Status as Status4
,A4.Entered as Entered4
,A5.Status as Status5
,A5.Entered as Entered5
,A6.Status as Status6
,A6.Entered as Entered6
,A7.Status as Status7
,A7.Entered as Entered7
,A8.Status as Status8
,A8.Entered as Entered8
From A
Left Join A as A2
on A2.JobNo = A.JobNo and A2.StatusOrder = 2
Left Join A as A3
on A3.JobNo = A.JobNo and A3.StatusOrder = 3
Left Join A as A4
on A4.JobNo = A.JobNo and A4.StatusOrder = 4
Left Join A as A5
on A5.JobNo = A.JobNo and A5.StatusOrder = 5
Left Join A as A6
on A6.JobNo = A.JobNo and A6.StatusOrder = 6
Left Join A as A7
on A7.JobNo = A.JobNo and A7.StatusOrder = 7
Left Join A as A8
on A8.JobNo = A.JobNo and A8.StatusOrder = 8
Where A.StatusOrder = 1
答案 2 :(得分:0)
我确实知道这是不是你想要的。我创建了一个获取JobNo的代码,并根据时间显示它的所有状态。
表
CREATE TABLE ##JobStatusLog (JobStatusNo int , JobNo int, Status int, Rem varchar(25) , Entered datetime, EnteredBy int )
CREATE TABLE ##tmpJobStatusLog (JobNo int, Status int,Entered datetime, Sequence int , StatusName varchar(20) , EnteredName varchar(20))
CREATE TABLE ##StatusSequence(Sequence int, StatusName varchar(20) , EnteredName varchar(20))
数据加载
Insert ##JobStatusLog (JobStatusNo ,JobNo ,Status ,Rem ,Entered ,EnteredBy) values
(1644897 ,420969 ,801 ,'Reschedule' ,'2017-09-20 17:58:18.503', 1488)
,(1644896 ,420969 ,812 ,'Cancelled' ,'2017-09-15 08:20:48.390', 1267)
,(1644895 ,420969 ,803 ,'Confirmed' ,'2017-09-14 10:13:25.733', 1231)
,(1644894 ,420969 ,802 ,'Call Bob ' ,'2017-09-14 09:35:57.337', 1231)
,(1644893 ,420969 ,801 ,' ' ,'2017-09-08 18:18:16.490', 1488)
,(1644892 ,420968 ,801 ,' ' ,'2017-09-20 17:55:02.660', 1488)
,(1644891 ,420967 ,801 ,' ' ,'2017-09-20 17:47:52.340', 1488)
,(1644890 ,420966 ,801 ,' ' ,'2017-09-20 17:40:22.580', 1488)
,(1644880 ,420965 ,803 ,'Confirmed' ,'2017-09-20 17:05:30.870', 1193)
,(1644879 ,420965 ,801 ,' ' ,'2017-09-20 17:05:29.130', 1193)
,(1644877 ,420964 ,801 ,' ' ,'2017-09-20 17:02:16.830', 1193)
准备数据
;WITH CTE
AS
(
SELECT
*
, Sequence = ROW_NUMBER() OVER (PARTITION BY JobNo ORDER BY Entered)
FROM
##JobStatusLog
)
INSERT ##tmpJobStatusLog
SELECT JobNo , Status ,Entered , Sequence , 'Status' + CAST(Sequence as varchar(9)) StatusName , 'Entered' + CAST(Sequence as varchar(9)) EnteredName
FROM CTE ORDER BY Status
准备列名
INSERT ##StatusSequence
SELECT DISTINCT Sequence ,StatusName, EnteredName FROM ##tmpJobStatusLog
declare @sql nvarchar(max) =''
declare @columnsStatus nvarchar(max) =''
declare @columnsEntered nvarchar(max) =''
declare @columnsFinal nvarchar(max) =''
Select @columnsStatus = @columnsStatus + N'[' + StatusName + N'],' from ##StatusSequence
Select @columnsEntered = @columnsEntered + N'[' + EnteredName + N'],' from ##StatusSequence
Select @columnsFinal = @columnsFinal + N'[' + StatusName + N'],' + N'[' + EnteredName + N'],'
from ##StatusSequence
执行
SET @sql = N';WITH Status AS
(
select JobNo,' + Left(@columnsStatus, Len(@columnsStatus) - 1) + N' from (
select a.JobNo,b.StatusName, a.Status from ##tmpJobStatusLog a left join ##StatusSequence b on a.Sequence = b.Sequence
) as St pivot ( max(Status) for StatusName in ( ' + Left(@columnsStatus, Len(@columnsStatus) - 1) + N') ) pvt),
Entered AS (select JobNo,' + Left(@columnsEntered, Len(@columnsEntered) - 1) + N' from (
select a.JobNo,b.EnteredName, a.Entered from ##tmpJobStatusLog a left join ##StatusSequence b on a.Sequence = b.Sequence
) as St pivot ( max(Entered) for EnteredName in ( ' + Left(@columnsEntered, Len(@columnsEntered) - 1) + N') ) pvt
)
SELECT A.JobNo ,' + Left(@columnsFinal, Len(@columnsFinal) - 1) + N' FROM
Status A
INNER JOIN Entered B
On
A.JobNo = B.JobNo'
exec sp_executesql @sql
结果
JobNo Status1 Entered1 Status2 Entered2 Status3 Entered3 Status4 Entered4 Status5 Entered5
----------- ----------- ----------------------- ----------- ----------------------- ----------- ----------------------- ----------- ----------------------- ----------- -----------------------
420964 801 2017-09-20 17:02:16.830 NULL NULL NULL NULL NULL NULL NULL NULL
420965 801 2017-09-20 17:05:29.130 803 2017-09-20 17:05:30.870 NULL NULL NULL NULL NULL NULL
420966 801 2017-09-20 17:40:22.580 NULL NULL NULL NULL NULL NULL NULL NULL
420967 801 2017-09-20 17:47:52.340 NULL NULL NULL NULL NULL NULL NULL NULL
420968 801 2017-09-20 17:55:02.660 NULL NULL NULL NULL NULL NULL NULL NULL
420969 801 2017-09-08 18:18:16.490 802 2017-09-14 09:35:57.337 803 2017-09-14 10:13:25.733 812 2017-09-15 08:20:48.390 801 2017-09-20 17:58:18.503