2017-03-23 18 views
18

背景には2つの時刻の差を取得:SQL Server 2012の

私は顧客が特定の部屋で過ごす時間の長さを特定しようとしています。各顧客はCustomerIDで識別でき、訪問するとVisitNumberとなります。例えば、顧客は、今日訪れた場合、彼らはのVisitNumber彼らはその後、離れて、来週戻ってくる111111を言うになるだろうし、彼らが最初に部屋を割り当てられていないVisitNumber

111112.の場合には、顧客最初の訪問を持っているでしょう最終的に指定された部屋が割り当てられると、データベースにエントリが書き込まれます。 CurrentRoomはまだ部屋がないため空白になり、NewRoomは移動された部屋になります。

このエントリは、イベント1(顧客が部屋から部屋に移動したこと)として記録され、トランザクションが行われる時刻です。 滞在中に顧客が今後移動する場合は、イベント9(顧客が部屋から別の部屋に移動した場合)として記録されるの滞在と、CurrentRoom & * の値が記録されます。

私は前の行からの時間を取得するために管理していると、次の行からの時間がLAGLEADを使用して、違いをうまく問題

顧客がその特定の部屋に費やした時間の長さを2倍にします。

LAGを使用する際の問題は、以前の値を取得していることであり、場合によっては完全に異なる顧客の値である可能性があります。私は、特定のCustomerID &ためLAG & LEAD値現在VisitNumberを取得し、顧客が部屋で過ごしたことをどのくらいを見つけるために値の差をうまくしたいと思います。

デモデータ:

CREATE TABLE #beds 
(
    [id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    [User] [nvarchar](50) NULL, 
    [CustomerID] [nvarchar](50) NULL, 
    [Area] [nchar](10) NULL, 
    [Event] [nvarchar](50) NULL, 
    [VisitNumber] [nvarchar](50) NULL, 
    [Time] [datetime] NULL, 
    [CurrentRoom] [nvarchar](50) NULL, 
    [NewRoom] [nvarchar](50) NULL 
) 
GO 

INSERT INTO #beds ([User],[CustomerID],[Area],[Event],[VisitNumber],[Time],[CurrentRoom],[NewRoom]) 
VALUES ('00001','C11111111','Area1',2,111111111,'2017-03-22 11:05:44.360','B22','B44'), 
('00001','C11111111','Area1',1,111111111,'2017-03-22 11:05:15.517','','B22'), 
('00001','C22222222','Area2',1,222222222,'2017-03-22 07:38:16.117','','POD3'), 
('00001','C22222222','Area2',3,222222222,'2017-03-22 07:41:24.787','POD3','POD3'), 
('00001','C22222222','Area2',9,222222222,'2017-03-22 09:10:49.697','POD3',''), 
('00001','C22222222','Area2',1,222222222,'2017-03-22 10:05:19.130','','POD15'), 
('00001','C22222222','Area2',2,222222222,'2017-03-22 10:13:43.057','POD15','A'), 
('00001','C22222222','Area2',3,222222222,'2017-03-22 10:25:01.527','A','A'), 
('00001','C22222222','Area2',3,222222222,'2017-03-22 10:46:03.960','A','A'), 
('00001','C22222222','Area2',3,222222222,'2017-03-22 10:46:17.030','A','A'), 
('00002','C33333333','Area3',1,333333333,'2017-03-22 09:20:23.660','','B46'), 
('00001','C33333333','Area2',9,333333333,'2017-03-22 08:53:32.860','POD8','POD1'), 
('00001','C33333333','Area2',1,333333333,'2017-03-22 07:34:58.810','POD7','POD8'), 
('00001','C33333333','Area2',1,333333333,'2017-03-22 11:49:55.203','','BB4'), 
('00001','C33333333','Area2',3,333333333,'2017-03-22 11:50:11.943','BB4','BB4'), 
('00001','C33333333','Area2',3,333333333,'2017-03-22 08:42:56.157','POD8','POD8'), 
('00001','C33333333','Area2',3,333333333,'2017-03-22 08:22:59.157','POD8','POD8'), 
('00003','C33333333','Area3',1,333333333,'2017-03-23 06:41:12.753','','B46') 

GO 

これは私がこれまで持っているクエリです。これは私に前の行の値と次の行の値を与えますが、私はそれが顧客を考慮に入れないと思います。

SELECT 
    T1.[User], T1.[CustomerID], 
    T1.[Area], T1.[Event], 
    T1.[VisitNumber], 
    T1.[CurrentRoom], T1.[NewRoom], 
    T1.[Time], 
    LAG(T1.TIME) OVER (ORDER BY T1.VisitNumber) PreviousTime, 
    LEAD(T1.TIME) OVER (ORDER BY T1.VisitNumber) NextTime 
FROM 
    #beds t1 
WHERE 
    T1.[Area] = 'Area2' 
    AND T1.[CurrentRoom] IS NOT NULL 
    AND T1.[NewRoom] IS NOT NULL 
    AND T1.[CustomerID] IS NOT NULL 
    AND T1.[CustomerID] <> ' ' 
    AND T1.Event IN (1,9) 
ORDER BY 
    VisitNumber DESC 

予想される出力:これは私が期待している出力です。私はしたいTimeInRoom(時間から日付フィールドを除く):

+------------+-------+-------------+-------------+---------+------------+ 
| CustomerID | Area | VisitNumber | CurrentRoom | NewRoom | TimeInRoom | 
+------------+-------+-------------+-------------+---------+------------+ 
|C33333333 |Area2 | 333333333 |    | BB4  | 00:10  | 
|C33333333 |Area2 | 333333333 |    | POD8 | 00:20  | 
|C33333333 |Area2 | 333333333 | POD8  |   | 00:30  | 
+------------+-------+-------------+-------------+---------+------------+ 
+2

これは良いSQLの質問をする方法の一例です。 +1。 –

+1

列が一致しないことを除いて... – jarlh

+0

@iamrichhowell:サンプルデータがあなたの説明と一貫性がありますか? – etsa

答えて

4

私はこれが役に立てば幸い:

;WITH cte_Result AS 
(
    SELECT 
     [CustomerID], 
     [Area], 
     [VisitNumber], 
     [CurrentRoom], 
     [NewRoom], 
     [Time], 
     LAG([TIME]) OVER (partition by [CustomerID],[VisitNumber] ORDER BY ID DESC) PreviousTime, 
     LEAD([TIME]) OVER (partition by [CustomerID],[VisitNumber] ORDER BY ID DESC) NextTime 
    FROM #beds 
    WHERE [Area] = 'Area2' 
     AND [CurrentRoom] IS NOT NULL 
     AND [NewRoom] IS NOT NULL 
     AND [CustomerID] IS NOT NULL 
     AND [CustomerID] <> ' ' 
     AND [Event] IN (1,9) 
     --AND [CustomerID] = 'C33333333' 
), 
cte_BuildStayPeriod 
AS (
    SELECT CustomerID, 
     Area, 
     VisitNumber, 
     CurrentRoom, 
     NewRoom, 
     DATEDIFF(SECOND, COALESCE([NextTime], PreviousTime), COALESCE(PreviousTime, [time])) AS StayDuration 
    FROM cte_Result 
) 
SELECT CustomerID, 
    Area, 
    VisitNumber, 
    CurrentRoom, 
    NewRoom, 
    StayDuration, 
    CAST(DATEADD(SECOND, StayDuration, '1900-01-01') AS TIME) AS StayDuration 
FROM cte_BuildStayPeriod 
+0

これは完璧に機能しました。ありがとうございました。 – sqlrich

4

私は非常によくあなたの質問を理解し、しかし、あなたのLAG/LEAD関数内の句PARTITION BYを使用しようとしなかったことがある:

,LAG(T1.TIME) OVER (PARTITION BY CustomerID ORDER BY T1.VisitNumber) PreviousTime 
,LEAD(T1.TIME) OVER (PARTITION BY CustomerID ORDER BY T1.VisitNumber) NextTime 
0

お客様の例では、顧客が一度訪れると問題が発生し、遅れ/鉛を使用すると別のクライアントの訪問情報が得られます。

はそれを試してみてください。

SELECT 
    T1.[User], T1.[CustomerID], 
    T1.[Area], T1.[Event], 
    T1.[VisitNumber], 
    T1.[CurrentRoom], T1.[NewRoom], 
    T1.[Time], 
    (select TOP (1) t.Time from #beds t where t.[CustomerID] = T1.[CustomerID] and t.Time<T1.Time order by t.Time desc) PreviousTime, 
    (select TOP (1) t.Time from #beds t where t.[CustomerID] = T1.[CustomerID] and t.Time>T1.Time order by t.Time) NextTime 
FROM 
    #beds t1 
WHERE 
    T1.[Area] = 'Area2' 
    AND T1.[CurrentRoom] IS NOT NULL 
    AND T1.[NewRoom] IS NOT NULL 
    AND T1.[CustomerID] IS NOT NULL 
    AND T1.[CustomerID] <> ' ' 
    AND T1.Event IN (1,9) 
ORDER BY 
    VisitNumber DESC