8

1時間、1日あたりのイベント数をカウントするクエリを作成しています。ほとんどの日はアクティビティがない時間帯があるため、クエリが実行されると1時間あたりのアクティビティ数が表示されますが、ギャップがあり、クエリはこれらを除外します。それでも、アクティビティがない時間を表示し、ゼロを表示して、ゼロ値をグラフ化できるようにします。使用しているクエリは次のようになります…</p>

select datepart(Year, dev_time) as Year,
    datepart(Month, dev_time) as Month,
    datepart(Day, dev_time) as Day,
    datepart(Hour, dev_time) as Hour,
    count(tdm_msg) as Total_ACTIVITES
from TCKT_ACT
where tdm_msg = ‘4162′ and dev_time >= DATEADD(day, - 1, GETDATE())
group by datepart(Year, dev_time) ,
    datepart(Month, dev_time) ,
    datepart(Day, dev_time),
    datepart(Hour, dev_time)
order by datepart(Year, dev_time) asc,
    datepart(Month, dev_time) asc,
    datepart(Day, dev_time) asc,
    datepart(Hour, dev_time) asc
4

5 に答える 5

3

どういうわけか日と時間のテーブルが必要になり、そのテーブルとクエリの間で外部結合を行う必要があります。これが私がそれをする方法です。このソリューションはSQLServer2005および2008でのみ機能することに注意してください。これらのプラットフォームがない場合は、データベースに実際に時間のテーブルを作成して、そこから参加できるようにする必要があります。

DECLARE @MinDate DATETIME;
SET @MinDate =  CONVERT(varchar, GETDATE(), 101);

WITH times AS (
    SELECT @MinDate as dt, 1 as depth
    UNION ALL
    SELECT DATEADD(hh, depth, @MinDate), 1 + depth as depth
    FROM times
    WHERE DATEADD(hh, depth, @MinDate) <= GETDATE())
SELECT DATEPART(YEAR, t.dt) as [Year],
    DATEPART(MONTH, t.dt) as [Month],
    DATEPART(DAY, t.dt) as [Day],
    DATEPART(HOUR, t.dt) as [Hour],
    COUNT(tdm_msg) as Total_ACTIVITES
FROM times t
LEFT JOIN (SELECT * FROM TCKT_ACT WHERE tdm_msg = '4162' and dev_time >= @MinDate) a
    ON  DATEPART(HOUR, t.dt)  = DATEPART(HOUR, a.dev_time)
    AND MONTH(t.dt) = MONTH(a.dev_time)
    AND DAY(t.dt)   = DAY(a.dev_time)
    AND YEAR(t.dt)  = YEAR(a.dev_time)
GROUP BY DATEPART(YEAR, t.dt) ,
    DATEPART(MONTH, t.dt) ,
    DATEPART(DAY, t.dt),
    DATEPART(HOUR, t.dt)
ORDER BY DATEPART(YEAR, t.dt) asc,
    DATEPART(MONTH, t.dt) asc,
    DATEPART(DAY, t.dt) asc,
    DATEPART(HOUR, t.dt) asc
OPTION (MAXRECURSION 0); /* Just in case you want a longer timespan later on... */

上部のWITHステートメントは再帰共通テーブル式と呼ばれ、ここにあるように、要素の数が比較的少ないシーケンシャルテーブルを生成するための優れた方法であることに注意してください。

于 2008-12-17T02:43:25.067 に答える
3

最初に、Dave Markle が説明した再帰的な共通テーブル クエリに基づいてテーブル関数を作成しました (この Dave を見せてくれてありがとう!)。関数を 1 回作成するだけで、任意の間隔の分析に使用できるため、これは非常に便利です。

if exists (select * from dbo.sysobjects where name = 'fn_daterange') drop function fn_daterange;
go

create function fn_daterange
   (
   @MinDate as datetime,
   @MaxDate as datetime,
   @intval  as datetime
   )
returns table
--**************************************************************************
-- Procedure: fn_daterange()
--    Author: Ron Savage
--      Date: 12/16/2008
--
-- Description:
-- This function takes a starting and ending date and an interval, then
-- returns a table of all the dates in that range at the specified interval.
--
-- Change History:
-- Date        Init. Description
-- 12/16/2008  RS    Created.
-- **************************************************************************
as
return
   WITH times (startdate, enddate, intervl) AS
      (
      SELECT @MinDate as startdate, @MinDate + @intval - .0000001 as enddate, @intval as intervl
         UNION ALL
      SELECT startdate + intervl as startdate, enddate + intervl as enddate, intervl as intervl
      FROM times
      WHERE startdate + intervl <= @MaxDate
      )
   select startdate, enddate from times;

go

したがって、その関数から選択を単独で実行すると、次のような時間間隔の表が得られます。

fn_daterange('12/14/2008 10:00:00', '12/14/2008 20:00:00', '01:00:00' )

戻り値:

startdate               enddate                 intervl                 
----------------------- ----------------------- ----------------------- 
2008-12-14 10:00:00.000 2008-12-14 10:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 11:00:00.000 2008-12-14 11:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 12:00:00.000 2008-12-14 12:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 13:00:00.000 2008-12-14 13:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 14:00:00.000 2008-12-14 14:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 15:00:00.000 2008-12-14 15:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 16:00:00.000 2008-12-14 16:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 17:00:00.000 2008-12-14 17:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 18:00:00.000 2008-12-14 18:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 19:00:00.000 2008-12-14 19:59:59.997 1900-01-01 01:00:00.000 
2008-12-14 20:00:00.000 2008-12-14 20:59:59.997 1900-01-01 01:00:00.000 

次に、イベント データのサンプル テーブルを作成しました。

    eventdate               eventnote            
    ----------------------- -------------------- 
    2008-12-14 10:01:00.000 oo! an event!        
    2008-12-14 10:01:00.000 oo! an event!        
    2008-12-14 10:01:00.000 oo! an event!        
    2008-12-14 10:01:00.000 oo! an event!        
    2008-12-14 10:23:00.000 oo! an event!        
    2008-12-14 10:23:00.000 oo! an event!        
    2008-12-14 10:23:00.000 oo! an event!        
    2008-12-14 11:23:00.000 oo! an event!        
    2008-12-14 11:23:00.000 oo! an event!        
    2008-12-14 11:23:00.000 oo! an event!        
    2008-12-14 11:23:00.000 oo! an event!        
    2008-12-14 11:23:00.000 oo! an event!        
    2008-12-14 14:23:00.000 oo! an event!        
    2008-12-14 14:23:00.000 oo! an event!        
    2008-12-14 14:23:00.000 oo! an event!        
    2008-12-14 19:23:00.000 oo! an event!        
    2008-12-14 19:23:00.000 oo! an event!        
    2008-12-14 19:23:00.000 oo! an event!        
    2008-12-14 19:23:00.000 oo! an event!        
    2008-12-14 19:00:00.000 oo! an event!        
    2008-12-14 19:00:00.000 oo! an event!        
    2008-12-14 19:00:00.000 oo! an event!        

    22 Row(s) affected

次に、次のように LEFT OUTER JOIN でそれらを接続しました。

select
   dr.startdate,
   dr.enddate,
   count(me.eventdate) as eventcount
from
   fn_daterange('12/14/2008 10:00:00', '12/14/2008 20:00:00', '01:00:00' ) dr

   LEFT OUTER JOIN myevents me
      on ( me.eventdate between dr.startdate and dr.enddate)
group by
   dr.startdate,
   dr.enddate


startdate               enddate                 eventcount 
----------------------- ----------------------- ---------- 
2008-12-14 10:00:00.000 2008-12-14 10:59:59.993 7          
2008-12-14 11:00:00.000 2008-12-14 11:59:59.993 5          
2008-12-14 12:00:00.000 2008-12-14 12:59:59.993 0          
2008-12-14 13:00:00.000 2008-12-14 13:59:59.993 0          
2008-12-14 14:00:00.000 2008-12-14 14:59:59.993 3          
2008-12-14 15:00:00.000 2008-12-14 15:59:59.993 0          
2008-12-14 16:00:00.000 2008-12-14 16:59:59.993 0          
2008-12-14 17:00:00.000 2008-12-14 17:59:59.993 0          
2008-12-14 18:00:00.000 2008-12-14 18:59:59.993 0          
2008-12-14 19:00:00.000 2008-12-14 19:59:59.993 7          
2008-12-14 20:00:00.000 2008-12-14 20:59:59.993 0          

11 Row(s) affected

HOLY CRAP は甘いです - 仕事であらゆる種類の分析にこれを使用できます! :-)

質問をしてくれた Fred と、一般的なテーブル クエリに関する情報をくれた Dave に感謝します。

ロン

于 2008-12-17T05:36:30.727 に答える
2

一部のパフォーマンス監視ソフトウェアでも同様の問題が発生しましたが、DB2 / zメインフレームショップにいるため、この種の結果を得るためにSQL体操を行う必要はありません。取得するすべての行で「関数」を実行するSQLクエリは、スケーラブルではないことで有名であり、DBAがそれらを使用しようとすると、フィールドデーで私たちを笑わせてしまいます。

代わりに、データベーススキーマをリファクタリングして、各行にイベントの数を含める方が簡単であることがわかりました(DBAは、ディスク容量を増やしても、CPUの数を増やしてもかまいません)。あなたの場合、それはtdm_quantあなたが挿入するすべての行(すなわち、各イベント)に対して1に設定するという名前の列を追加することになるでしょう。

次に、クエリの5番目のフィールドが変更されcount(tdm_msg)sum(tdm_quant)同じ結果が得られます。

tdm_quantそれに加えて、フィールドがゼロに設定されている特別なレコード(1時間に1回、または毎日の開始時に24個、または必要に応じて1月1日に価値のある年全体を入力)を挿入できます。ゼロであるため、これらのレコードは影響を与えませんが、目的の動作が得られます。1日の時間ごとsum(tdm_quant)に行が返され、その時間にイベントが発生しなかった場合はゼロになります。Total_ACTIVITIES

クエリの残りの部分を変更する必要はありません。

于 2008-12-17T02:43:49.077 に答える
0

1から24までの数字が含まれる別のテーブルを使用して「左外部結合」を使用できるようです...

于 2008-12-17T02:47:56.477 に答える
0

ここでの基本的な答えは、左外部結合(LOJ)と、nullCOUNT(column)をカウントしないが、COUNT(*)がすべての行をカウントする明示的なものです。難しいのは、LOJを実行するためのテーブルを生成することです。WITH句と再帰的ソリューションは多くのDBMSで機能します(MS SQL Server、明らかに、そしてほぼ確実にDB2-おそらく他のものも)。

多くのDBMSは、一時テーブルとストアドプロシージャをサポートしています。この組み合わせを使用して、日付/時刻フィールドの適切な値のセットをテーブルに入力し、そのテーブルに対してLOJを実行できます(より正確には、FROM temp_table LEFT OUTER JOIN main_table ...)。きちんと整頓されていませんが、ほとんどの場所で機能します。

于 2008-12-17T03:29:53.350 に答える