2013-08-14 14 views
9

Ich hoffe du kannst mir helfen.Wie gruppiert man Zeilen nach DATEDIFF?

Ich muss die Datensätze in HH_Solution_Audit Tabelle anzeigen - wenn 2 oder mehr Mitarbeiter den Raum innerhalb von 10 Minuten betreten. Hier sind die Anforderungen:

  1. Zeigen Sie nur die Ereignisse mit einem Zeitstempelintervall (LAST_UPDATED) von weniger als oder gleich 10 Minuten an. Daher muss ich die aktuelle Zeile mit der nächsten Zeile und der vorherigen Zeile vergleichen, um zu überprüfen, ob ihr DATEDIFF kleiner oder gleich 10 Minuten ist. Ich bin mit diesem Teil fertig.
  2. zeigen die Aufzeichnungen nur dann, wenn die Anzahl der verschiedenen STAFF_GUID im Raum für weniger als oder gleich 10 Minuten beträgt mindestens 2.

HH_Solution_Audit Tabelle Details:

  1. ID - PK
  2. STAFF_GUID - Personal-ID
  3. LAST_UPDATED - Datumzeit, wenn ein Mitarbeiter ein Zimmer
01 eintritt

Hier ist, was ich bis jetzt bekommen habe. Dies erfüllt nur die Anforderung Nr. 1.

CREATE TABLE HH_Solution_Audit (
ID INT PRIMARY KEY, 
STAFF_GUID NVARCHAR(1), 
LAST_UPDATED DATETIME 
) 
GO 
INSERT INTO HH_Solution_Audit VALUES (1, 'b', '2013-04-25 9:01') 
INSERT INTO HH_Solution_Audit VALUES (2, 'b', '2013-04-25 9:04') 
INSERT INTO HH_Solution_Audit VALUES (3, 'b', '2013-04-25 9:13') 
INSERT INTO HH_Solution_Audit VALUES (4, 'a', '2013-04-25 10:15') 
INSERT INTO HH_Solution_Audit VALUES (5, 'a', '2013-04-25 10:30') 
INSERT INTO HH_Solution_Audit VALUES (6, 'a', '2013-04-25 10:33') 
INSERT INTO HH_Solution_Audit VALUES (7, 'a', '2013-04-25 10:41') 
INSERT INTO HH_Solution_Audit VALUES (8, 'a', '2013-04-25 11:02') 
INSERT INTO HH_Solution_Audit VALUES (9, 'a', '2013-04-25 11:30') 
INSERT INTO HH_Solution_Audit VALUES (10, 'a', '2013-04-25 11:45') 
INSERT INTO HH_Solution_Audit VALUES (11, 'a', '2013-04-25 11:46') 
INSERT INTO HH_Solution_Audit VALUES (12, 'a', '2013-04-25 11:51') 
INSERT INTO HH_Solution_Audit VALUES (13, 'a', '2013-04-25 12:24') 
INSERT INTO HH_Solution_Audit VALUES (14, 'b', '2013-04-25 12:27') 
INSERT INTO HH_Solution_Audit VALUES (15, 'b', '2013-04-25 13:35') 

DECLARE @numOfPeople INT = 2, 
       --minimum number of people that must be inside 
       --the room for @lengthOfStay minutes 
      @lengthOfStay INT = 10, 
       --number of minutes of stay 
      @dateFrom DATETIME = '04/25/2013 00:00', 
      @dateTo DATETIME = '04/25/2013 23:59'; 
    WITH cteSource AS 
    (
     SELECT ID, STAFF_GUID, LAST_UPDATED, 
       ROW_NUMBER() OVER (ORDER BY LAST_UPDATED) AS row_num 
     FROM HH_SOLUTION_AUDIT 
       WHERE LAST_UPDATED >= @dateFrom AND LAST_UPDATED <= @dateTo 
    ) 
    SELECT [current].ID, [current].STAFF_GUID, [current].LAST_UPDATED 
    FROM 
     cteSource AS [current] 
    LEFT OUTER JOIN 
     cteSource AS [previous] ON [current].row_num = [previous].row_num + 1 
    LEFT OUTER JOIN 
     cteSource AS [next] ON [current].row_num = [next].row_num - 1 
    WHERE 
     DATEDIFF(MINUTE, [previous].LAST_UPDATED, [current].LAST_UPDATED) 
     <= @lengthOfStay 
     OR 
     DATEDIFF(MINUTE, [current].LAST_UPDATED, [next].LAST_UPDATED) 
     <= @lengthOfStay 
    ORDER BY [current].ID, [current].LAST_UPDATED  

dem Ausführen der Abfrage zurückgegeben IDs:
1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14
That erfüllt die Anforderung Nr. 1 mit einem Intervall von weniger als oder gleich 10 Minuten zwischen der vorherigen Zeile, der aktuellen Zeile und der nächsten Zeile.

Können Sie mir mit der 2. Anforderung helfen? Wenn es angewendet wird, sollte die zurückgegebenen IDs nur lauten:
13, 14

+4

können Sie Setup 'Letzten' ein Beispieldaten? Wenige Zeilen und erwartetes Ergebnis auf ihnen? –

+2

Die Frage ist wirklich Gott, und ich kann sehen, dass Sie wirklich versuchen, aber wir könnten Ihnen mehr helfen, wenn Sie einige Beispiele geben. Vielen Dank! – GianlucaBobbio

+0

@NenadZivkovic Hallo Nenad. Ich fügte Beispieldaten und erwartetes Ergebnis wie gewünscht hinzu. Vielen Dank. Ich habe das vergessen. – Raii

Antwort

3

Hier eine Idee. Sie benötigen ROW_NUMBER und vorherige und nächste Datensätze nicht. Sie müssen nur unioned abfragen - einer sucht nach jedem, der X Minuten hinter sich hat, und einem anderen, der X Minuten im Voraus sucht. Jeder verwendet eine korrelierte Unterabfrage und COUNT (*), um die Anzahl der übereinstimmenden Personen zu finden. Wenn die Nummer größer ist als Ihre @numOfPersonen - das war's.

BEARBEITEN: neue Version: Statt zwei Abfragen mit 10 Minuten im Voraus und hinter, werden wir nur für 10 Minuten nach - Wählen Sie diejenigen, die in CteLastOnes übereinstimmen. Danach wird in einem anderen Teil der Abfrage nach denen suchen, die tatsächlich innerhalb dieser 10 Minuten existieren. Letztlich macht wieder Vereinigung von ihnen und der

WITH cteSource AS 
(
    SELECT ID, STAFF_GUID, LAST_UPDATED 
    FROM HH_SOLUTION_AUDIT 
    WHERE LAST_UPDATED >= @dateFrom AND LAST_UPDATED <= @dateTo 
) 
,cteLastOnes AS 
(
    SELECT * FROM cteSource c1 
    WHERE @numOfPeople -1 <= (SELECT COUNT(DISTINCT STAFF_GUID) 
           FROM cteSource c2 
           WHERE DATEADD(MI,@lengthOfStay,c2.LAST_UPDATED) > c1.LAST_UPDATED 
           AND C2.LAST_UPDATED <= C1.LAST_UPDATED 
           AND c1.STAFF_GUID <> c2.STAFF_GUID) 
) 
SELECT * FROM cteLastOnes 
UNION 
SELECT * FROM cteSource s 
WHERE EXISTS (SELECT * FROM cteLastOnes l 
       WHERE DATEADD(MI,@lengthOfStay,s.LAST_UPDATED) > l.LAST_UPDATED 
       AND s.LAST_UPDATED <= l.LAST_UPDATED 
       AND s.STAFF_GUID <> l.STAFF_GUID) 

SQLFiddle DEMO - new version

SQLFiddle DEMO - old version

+0

Vielen Dank Nenad! Ich liebe seine Einfachheit! – Raii

+1

@ Raii NP. Sie sollten "COUNT (*)" durch "COUNT (Distinct STAFF_GUID)" ersetzen, um sicherzustellen, dass nur einzelne Mitarbeiter gezählt werden. In diesem Beispiel ist es irrelevant, aber es könnte einen Unterschied machen, wenn Sie '@ numOfPeople' größer als 2 haben. –

+0

Nenad, sehe ich. Ich werde Ihr Skript spielen, um den Unterschied in COUNT zu sehen. Ich liebe seine Logik. Ich habe nicht darüber nachgedacht, meine Aufgabe so zu machen. Danke noch einmal. – Raii

Verwandte Themen