2017-09-21 2 views
0

SQL Server 2012. Ich muss eine Abfrage erstellen, um festzustellen, welche Jobs in welchem ​​Status zu einem bestimmten Datum in der Vergangenheit waren (BONUS: wie lange sie in diesem Status waren.)SQL Konvertieren von Zeilen in Spalten zum Verfolgen des Jobstatus

ich habe eine Log-Tabelle Jobstatus mit den folgenden Spalten und Struktur:

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 

ich glaube, ich möchte eine bestimmte Auftragsnummer von jedem Status, war es in gefolgt haben, und wenn (plus I don sich nicht um Anmerkungen kümmern oder wer den Job eingegeben hat):

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 

... mit mehreren Spalten nach Angabe von 3Status und 3Entered usw. Ich muss nur für 8 Status/eingegebene Daten codieren, da dies die größte Anzahl von Malen ist, die ein Auftrag im Status neu geordnet oder ersetzt wird. Wenn es schließlich mehr Spalten gibt, kann ich jede Antwort, die ich hier bekomme, auf diese Logik erweitern.

... weil meine eventuelle "Antwort" am 1. Juli 2016 (irgendein gegebenes Datum) sein wird: 87 Jobs waren in 801 Status, 255 Jobs waren in 806 Status und 5 Jobs waren in 809 Status. Tatsächlich muss ich Mathe machen, um zu bestimmen, WIE LANGE JEDER ARBEITSPLATZ AM BESONDEREN STATUS WAR, aber da dies meine erste Frage ist und ich nicht weiß, wie kompliziert meine Antwort sein wird, rufe ich sie hier an, wie ich ' Ich denke, ich kann den Rest herausfinden, sobald ich diese Status und Daten mit DateDiff säulenartig erhalten habe.

Ich habe jede Kombination aus UNPIVOT, Lag/Lead, Gruppierung, MAX und so weiter ausprobiert und kann nirgends hinkommen.

An diesem Punkt vermisse ich vielleicht sogar etwas Einfaches und fühle mich ziemlich dumm bei der Antwort, aber ich bin wirklich und fest stecken. Werde ich sogar den richtigen Weg gehen und versuchen, diese Spalten aus den Reihen herauszuholen, in denen sie sich gerade befinden? Gibt es eine Möglichkeit, das angegebene Datum zu verwenden und die Tabelle so zu verwenden, wie sie ist? Wenn etwas nicht klar ist, werde ich versuchen, in Updates oder Antworten zu klären. Prost!

Und hier ist die Antwort, die ich von @Fercstar wählte:

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 

Läuft in 12 Sekunden gegen über einer Million Datenzeilen ohne temporäre Tabelle Management erforderlich. ELEGANT! Danke @Fercstar.

+0

Danke John Cappelletti für die Neuformatierung! Viel besser lesbar. – DataVis4Fun

Antwort

0

Sie

ROW_NUMBER() OVER(PARTITION BY JobNo ORDER BY Entered DESC) 

verwenden können, dass die Reihenfolge der Zustände erhalten wird durch Job mit 1 ist der jüngste. Sie können dann um diesen Punkt drehen.

Bearbeiten - Vollständige Abfrage basierend auf Beispieldaten

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 Ich habe meine Antwort so aktualisiert, dass sie eine vollständige Abfrage enthält, die unter Verwendung der Beispieldaten die gewünschten Ergebnisse liefert. Sie können den Unterschied zwischen den Zeitstempeln berechnen, wenn Sie sehen möchten, wie lange es in jedem Status war. – Fercstar

+0

Danke! Dies ist komprimiert, klar und ich kann folgen, was Sie getan haben und erweitern Sie es. Ich konnte leicht zusätzliche Spalten hinzufügen und kann mich auf die Berechnung dessen, was wann war, beziehen. Eine elegante und ausgezeichnete Lösung für mein Problem. Ich schätze Ihre Zeit bei der Beantwortung dieser Frage. – DataVis4Fun

0

Wenn Sie eine begrenzte num von Status haben, können Sie es verwenden

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  

Ergebnis

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

Dies funktioniert nur für die ersten beiden Spalten und wenn sie einen bestimmten Status haben ... aber wie bekomme ich die dritte, vierte, fünfte usw. Statusspalten und eingegeben? Ich habe Status, über die ich mich interessiere: 806.807.808.809 und 813 mit der Möglichkeit, dass jeder Job in jedem Status zuerst, als nächster oder als letzter ist. Ich habe 5 Status und die Möglichkeit, dass jeder Status einige Male verwendet wird, bis zu 8 oder mehr Spalten in der Ergebnisabfrage. Das bringt mich nicht aus einer harten Codierungssituation heraus, die nicht funktionieren wird. – DataVis4Fun

+0

Ich werde eine andere Antwort darauf erstellen. –

0

ich wusste, wenn es ist, was Sie wollen. Ich habe einen Code erstellt, der die JobNo bekommt und den gesamten Status auf der Basis der Zeit anzeigt.

Tabellen

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)) 

Datenlast

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) 

die Daten vorbereiten

;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 

die Spaltennamen vorbereiten

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 

Ausführen

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 

Ergebnis

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, das ist der neue Verstärker. –

+0

Um die Daten zwischen den Status zu berechnen, müssen Sie etwas wie ich mit @columnsFinal –

+0

erstellen Ich mag das, aber wenn ich es in meiner Testumgebung einrichten bekomme ich 53 Status und Spalten eingegeben, während es nur 9 Instanzen in der Daten. Ich habe versucht, die "letzten" Spalten zu verwenden, die Sie festgelegt haben, aber ich kann die Mathematik nicht dazu bringen, daran zu arbeiten, dass nur die Spalten mit den Daten angezeigt werden. Nachdem ich das gesagt habe, habe ich ein wenig gelernt, indem ich deinen Code benutzt und modifiziert habe, also DANKE! – DataVis4Fun

Verwandte Themen