2017-05-30 6 views
0

私はこれを序文にしておきますが、最初にこの質問をどのようにして答えを見つけることに大きな妨げになっているのか正確にはわかりません。その結果、私は完全に間違った用語を使用している可能性があります。TSQLのローリングカウント

ウィンドウを使用してある期間にわたって別個のユーザーの数を取得したいと考えています。

私のデータテーブルには、Id、User、RequestedOn、システムによって時間とともにキャプチャされるクエリの列があります。例えば、8時間の間に、システムは78人の異なるユーザーによって異なる回数370回照会される。

私はこれをブルートフォースで行い、無視する方法を考えましたが(BF & I)、多くのBF &のように、Beanの規模を拡大することはできません。

これらの例では、カウントするウィンドウサイズは8時間です。所与の8時間のタイムスロットに対する別個のユーザの数。

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' 

私はこれを行うより良い方法があると思いますが、どこから見てもわからないと思います。

ポインタが素晴らしいです!

+0

はあなたには、いくつかのサンプルデータと予想される出力を提供することができます:あなたはあなたのクエリを書き換えたい場合は

、あなたはこのような何かを行うことによって開始することができますか? – tarheel

答えて

1

私が正しく理解していれば、あなたが必要とするこのようなrecursive cte

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

これは魔法のようなもので、私が必要とするものは何でもしています。また、共通テーブル表現の概念を紹介しています。これは、私が何かを知りませんでしたし、もっと読むことが必要です。どうもありがとうございます! (そして、はい、UserIdのカウントはおそらく長期的には速くなるでしょう) – amber

+0

あなたはようこそ@amber – TriV

1

あなたは、あまりにも多くのことを変更することなく、既存のクエリの性能も最適化UNION ALLUNIONを交換し、上のいくつかのインデックスを追加したい場合Username列とRequestedOn列。

vwRequestsは、表(ビューではなく)である場合は、あなたのための最高の作品かを確認するためにこれらを試してみてください。

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

vwRequestsがビューである場合は、ベーステーブルの上にインデックスを追加または変更してみてくださいビューはインデックス付きビューになります。

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

ありがとう!これは私が必要とするものではありません。それは容易にスケールのように見えませんが、動作します。しかし、これは私を見上げて、学び、歩き回るための新しいものを与えました。そのために私は感謝しており、それゆえアップヴォートです。 <3 – amber