ソースデータがない場合にゼロの統計情報を取得する

特定の期間に特定の統計を提供するという問題が非常に頻繁に発生します。 たとえば、システムユーザーが先週実行した有用なアクションの数。 簡単なことは何もないように思われます。



SELECT Data, COUNT(*)

FROM tbl

WHERE Data BETWEEN SYSDATE-7 AND SYSDATE

GROUP BY Data

ORDER BY Data









1週間で、5つの行を取得する予定です-1営業日ごとに1行。 すべてが機能します。 ユーザーが1日に少なくとも1つのアクションを実行する限り。 テーブルに日付のある単一の行がない場合、結果として結果はありません。 また、レポートの予想される5行の代わりに、4 ...または3 ...またはまったくないことになります。 そして、ユーザーはゼロではあるものの5つを見たいと思っています!





解決策は、データを含むテーブルを、日付をリストする別のテーブルにリンクすることです。 日付をリストすることはできますが、顧客は数か月、明日、希望する年の統合レポートを望んでいました。 繰り返しますが、テーブルを作成するには、すでに月と年がありますか? あまり便利ではなく、面白​​くない。 しかし、これらのテーブルをその場で「エミュレート」しようとするとどうなりますか? 結局、関数は純粋なSQLでの使用に適したデータセットを返すことができます。 これを行うには、補助タイプが必要です。



CREATE OR REPLACE TYPE TDate_Sequence AS TABLE OF DATE;

/









そして、実際には、関数自体:



CREATE OR REPLACE FUNCTION Generate_Date_Sequence( -- - .

Data_Beg DATE, /* .*/

Data_End DATE, /* .*/

Step CHAR) /* : D - , M - , Y - .*/

RETURN TDate_Sequence

AS

data_curr DATE;

stp CHAR;

Result TDate_Sequence := TDate_Sequence();

BEGIN

stp := UPPER(Step);

IF stp = 'D' THEN

data_curr := TRUNC(Data_Beg, 'DD');

ELSIF stp = 'M' THEN

data_curr := TRUNC(Data_Beg, 'MM');

ELSIF stp = 'Y' THEN

data_curr := TRUNC(Data_Beg, 'YYYY');

END IF;

-- .

WHILE data_curr <= Data_End LOOP

Result.EXTEND;

Result(Result.LAST) := data_curr;

IF stp = 'D' THEN

data_curr := data_curr + 1;

ELSIF stp = 'M' THEN

data_curr := ADD_MONTHS(data_curr, 1);

ELSIF stp = 'Y' THEN

data_curr := ADD_MONTHS(data_curr, 12);

END IF;

END LOOP;

-- .

RETURN Result;

END Generate_Date_Sequence;

/









利用可能なデータを生成されたシーケンスに接続します。



SELECT data_sequence.column_value Data, COUNT(tbl.Data)

FROM TABLE(CAST(Generate_Date_Sequence(SYSDATE-30,SYSDATE,'D') AS TDate_Sequence)) data_sequence, tbl

WHERE tbl.Data(+) = data_sequence.column_value

GROUP BY data_sequence.column_value

ORDER BY data_sequence.column_value









...そして、お客様が希望するゼロを取得します!



All Articles