2017-09-21 15 views
0

SQL Server 2012.我需要创建一个查询来确定哪些作业在过去的任何给定日期处于哪种状态(BONUS:它们处于该状态的时间有多长)。SQL将行转换为列以跟踪作业状态

我有以下的列和结构的工作状态记录表:

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

谢谢约翰·卡佩莱蒂的格式化!更可读。 – DataVis4Fun

回答

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 
+0

@ DataVis4Fun我更新了我的答案,以包含一个完整的查询,使用您的示例数据返回所需的结果。您可以计算时间戳之间的差异,如果您想查看每个状态中的时间长度。 – Fercstar

+0

谢谢!这是压缩的,清晰的,我可以按照你所做的和扩展它。我能够轻松地添加其他列,并可以继续前进到什么时候的数学。我的问题的优雅和出色的解决方案。我很感谢你回答这个问题。 – DataVis4Fun

0

如果你有身份地位的有限NUM你可以用它

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 
+0

这只适用于前两列,如果他们是一个特定的状态......但我如何获得状态的第三,第四,第五等列和进入?我有关于我关心的状态:806,807,808,809和813,可能有任何工作处于任何状态,首先是下一个或最后一个状态。我有5个状态,每个状态被使用几次的可能性,最多8个结果查询列。这并没有让我摆脱硬编码的局面,这是行不通的。 – DataVis4Fun

+0

我会为它创建另一个答案。 –

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 
+0

@ DataVis4Fun,这是新的安装程序。 –

+0

要计算状态之间的数据,您需要创建类似于@columnsFinal –

+0

的样子,但是当我在测试环境中设置它时,我获得了53个状态并输入了列,而只有9个实例数据。我尝试过使用你设置的“最终”列,但不能让数学工作,只做数据显示的列。话虽如此,我通过使用和修改您的代码了解了一点,所以谢谢! – DataVis4Fun