2017-05-30 6 views
0

Lassen Sie mich dies vorwegnehmen mit Ich bin nicht genau sicher, wie man diese Frage in erster Linie stellen, die eine große Behinderung bei der Suche nach einer Antwort war. Als Ergebnis könnte ich eine völlig falsche Terminologie verwenden.Rollen zählt mit TSQL

Ich möchte die Anzahl der einzelnen Benutzer über einen bestimmten Zeitraum mit einem Fenster ermitteln.

Meine Datentabelle hat folgende Spalten: Id, User, RequestedOn, Query wo Anfragen im Laufe der Zeit vom System erfasst werden. Zum Beispiel wird das System innerhalb von acht Stunden von 78 verschiedenen Benutzern 370 verschiedene Male abgefragt.

Ich habe herausgefunden, wie dies durch rohe Gewalt zu tun und zu ignorieren (BF & I), aber wie viele BF & ich nähert, skaliert es nicht wert Bohnen.

In diesen Beispielen beträgt die Fenstergröße für das Zählen 8 Stunden; die Anzahl der verschiedenen Benutzer für einen bestimmten 8-Stunden-Zeitschlitz.

Select '5/28/17 15:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 15:00' And [RequestedOn] <= '5/28/17 23:00' Union 
Select '5/28/17 14:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 14:00' And [RequestedOn] <= '5/28/17 22:00' Union 
Select '5/28/17 13:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 13:00' And [RequestedOn] <= '5/28/17 21:00' Union 
Select '5/28/17 12:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 12:00' And [RequestedOn] <= '5/28/17 20:00' Union 
Select '5/28/17 11:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 11:00' And [RequestedOn] <= '5/28/17 19:00' Union 
Select '5/28/17 10:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 10:00' And [RequestedOn] <= '5/28/17 18:00' Union 
Select '5/28/17 09:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 09:00' And [RequestedOn] <= '5/28/17 17:00' Union 
Select '5/28/17 08:00' [StartingFrom], Count(Distinct [UserName]) [Users] From [vwRequests] Where [RequestedOn] >= '5/28/17 08:00' And [RequestedOn] <= '5/28/17 16:00' 

ich dort Figur hat doch ein besserer Weg, dies zu tun, aber ich weiß nicht, wo sogar Beginn der Suche.

Zeiger wären fantastisch!

+0

Können Sie einige Beispieldaten und erwartete Ausgabe zur Verfügung stellen? – tarheel

Antwort

1

Wenn ich mich richtig zu verstehen, müssen Sie ein recursive cte wie diese

DECLARE @StartTime datetime = '2017-05-28 00:00:00' 
DECLARE @EndTime datetime = '2017-05-29 00:00:00' 

;WITH cte AS 
(
    SELECT @StartTime AS StartPeriod, dateadd(hour,8,@StartTime) AS EndPeriod 
    UNION ALL 
    SELECT dateadd(hour,1,StartPeriod), dateadd(hour,1,EndPeriod) AS EndPeriod 
    FROM cte 
    WHERE cte.StartPeriod < @EndTime 
) 
-- cte returns 
--StartPeriod    EndPeriod 
--2017-05-28 00:00:00.000 2017-05-28 08:00:00.000 
--2017-05-28 01:00:00.000 2017-05-28 09:00:00.000 
--2017-05-28 02:00:00.000 2017-05-28 10:00:00.000 
--2017-05-28 03:00:00.000 2017-05-28 11:00:00.000 
--2017-05-28 04:00:00.000 2017-05-28 12:00:00.000 
--2017-05-28 05:00:00.000 2017-05-28 13:00:00.000 
--................. 
SELECT c.StartPeriod, c.EndPeriod, Users FROM cte c 
OUTER APPLY (
      SELECT Count(Distinct [UserName]) AS Users -- i think you should use Count(distinct UserId) instead of UserName 
      From [vwRequests] Where [RequestedOn] BETWEEN c.StartPeriod AND c.EndPeriod 
     ) ca 
OPTION (MAXRECURSION 0) 
+0

Das ist magisch und macht alles was ich brauche. Es führt mich auch in das Konzept der gemeinsamen Tabellenausdrücke ein, über die ich nichts wusste und mehr zu lesen habe. Ich danke dir sehr! (Und ja, UserId wird auf lange Sicht wahrscheinlich schneller sein.) – amber

+0

Sie sind herzlich willkommen @amber – TriV

1

Wenn Sie die Performace der vorhandenen Abfrage optimieren wollen, ohne es zu viel zu ändern, ersetzen UNION mit UNION ALL und ein paar Indizes für das hinzufügen Benutzername und RequestedOn-Spalten.

Wenn vwRequests ist eine Tabelle (keine Sicht), versuchen Sie diese zu sehen, was am besten für Sie:

CREATE INDEX IX1 ON dbo.vwRequests (RequestedOn, Username) 
CREATE INDEX IX2 ON dbo.vwRequests (Username, RequestedOn) 

Wenn vwRequests eine Ansicht ist, können Sie versuchen, Indizes für die Basistabelle hinzugefügt oder das Ändern Ansicht als indizierte Sicht.

Wenn Sie Ihre Abfrage neu schreiben möchten, können Sie, indem Sie so etwas wie dieses starten:

SELECT x1.StartingFrom, x2.Users 
FROM (VALUES (8),(9),(10),(11),(12),(13),(14),(15)) h (h) 
CROSS APPLY (
    SELECT DATEADD(HOUR,h,'20170528') AS [StartingFrom] 
) x1 
CROSS APPLY (
    SELECT COUNT(DISTINCT vr.Username) AS Users 
    FROM dbo.vwRequests vr 
    WHERE vr.RequestedOn BETWEEN x1.StartingFrom AND DATEADD(HOUR,8,x1.StartingFrom) 
) x2 
+0

Vielen Dank! Das ist nicht ganz das, was ich brauche; Es funktioniert, obwohl es nicht so aussieht, als ob es leicht skaliert. Dies gab mir jedoch neue Dinge zum Nachschlagen, Lernen und Trails zum Eintauchen. Dafür bin ich dankbar und daher die Anregung. <3 – amber