2017-03-23 15 views
18

के लिए दो बार के बीच का अंतर हो जाओ पृष्ठभूमि:SQL सर्वर 2012

मैं समय की लंबाई एक ग्राहक एक विशेष कमरे में खर्च करता है की पहचान करने की कोशिश कर रहा हूँ। प्रत्येक ग्राहक को CustomerID द्वारा पहचाना जा सकता है, और जब वे जाते हैं तो उन्हें VisitNumber असाइन किया जाता है। उदाहरण के लिए, यदि ग्राहक आज का दौरा किया वे की एक VisitNumber कहना 111111. वे तो छोड़ दें और अगले हफ्ते वापस आ जाएगा मिलेगा और एक की VisitNumber 111112.

जब किसी ग्राहक के पहली बार वे शुरू में एक कमरा आवंटित किया नहीं कर रहे हैं के लिए होता है , और जब उन्हें आखिरकार अपना नामित कमरा सौंपा जाता है तो डेटाबेस में एक प्रविष्टि लिखी जाती है। CurrentRoom खाली होगा क्योंकि उनके पास अभी तक कोई कमरा नहीं है, और NewRoom वह कमरा है जहां उन्हें स्थानांतरित किया गया है।

यह प्रविष्टि ईवेंट 1 के रूप में दर्ज की जाएगी (ग्राहक किसी कमरे से कमरे में नहीं जाता है), और वह समय होता है जब लेनदेन होता है। यदि ग्राहक को मौजूदा प्रवास के दौरान भविष्य में स्थानांतरित किया जाता है जिसे ईवेंट 9 (ग्राहक कमरे से दूसरे कमरे में स्थानांतरित किया जाता है) के रूप में रिकॉर्ड किया जाएगा, और CurrentRoom & * NewRoom मान भी रिकॉर्ड किए जाएंगे।

समस्या

मैं अंतराल का उपयोग कर पिछली पंक्ति और अगली पंक्ति से समय-समय पर पाने में कामयाब रहे है और लीड और फिर बाहर के बीच अंतर काम दो बार जो मुझे उस विशेष कमरे में बिताए गए समय की अवधि देता है।

एलएजी का उपयोग करते समय यह मुद्दा पिछले मान प्राप्त कर रहा है, जो कुछ मामलों में एक पूरी तरह से अलग ग्राहक से मूल्य हो सकता है। मैं केवल एक विशेष CustomerID & वर्तमान 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

इस तरह एक अच्छा एसक्यूएल सवाल पूछने के लिए पर एक प्रमुख उदाहरण है। +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

हो सकता है मैं बहुत अच्छी तरह से अपने प्रश्न समझ में नहीं आया, लेकिन अपने अंतराल/लीड कार्यों के अंदर खंड 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 
संबंधित मुद्दे