1

非常に単純化された、いくつかのサンプルデータを含む表:

action_date account_id
1/1/2010    123
1/1/2010    123
1/1/2010    456
1/2/2010    123
1/3/2010    789

上記のデータについては、次のようなクエリが必要です。

action_date num_events  num_unique_accounts  num_unique_accounts_wtd
1/1/2010    3           2                    2
1/2/2010    1           1                    2
1/3/2010    1           1                    3

ここでわかるように、num_unique_accounts_wtdは、一意の期間の一種のローリング終了日を示します...

最初は、フォームのクエリを考えるでしょう

WITH
    events AS
    (
        SELECT
            action_date
            , COUNT(account_id) num_events
            , COUNT(DISTINCT account_id) num_unique_accounts
        FROM     actions
        GROUP BY action_date
    )
SELECT
    action_date
    , num_events
    , num_unique_accounts
    , SUM(num_unique_accounts) OVER (PARTITION BY NEXT_DAY(action_date, 'Monday') - 7 ORDER BY action_date ASC) num_unique_accounts_wtd
FROM events

動作しますが、よく見ると、毎日num_unique_accountsが追加されます。クエリを実行すると、わかりやすくするために、2010年1月2日は、2+1のためにnum_unique_accounts_wtd=3になります。

何か案は?

編集:わかりやすくするために、データと出力の行をもう1つ追加しました

4

2 に答える 2

0

イベント クエリを 2 つに分割します。

WITH
    events1 AS
    (
        SELECT 
               NEXT_DAY(action_date, 1) - 7 week
             , action_date             
             , COUNT(account_id) num_events
             , COUNT(DISTINCT account_id) num_unique_accounts
        FROM     actions
        GROUP BY action_date
    ),
    events2 AS
    (
        SELECT NEXT_DAY(action_date, 1) - 7 week               
             , COUNT(DISTINCT account_id) num_unique_accounts_wtd
        FROM     actions
        GROUP BY NEXT_DAY(action_date, 1)
    )
SELECT events1.*, events2.num_unique_accounts_wtd
  FROM events1, events2 
 WHERE events1.week = events2.week

ここで、events1は 1 日の個別のアカウント数を選択し、 events2は 1 週間の個別のアカウント数を選択します。

編集:リクエストを理解しました。しかし、アクションテーブルの行数が非常に多い場合、私が持っている唯一の考えは非常に重くなるでしょう:

WITH
events AS
(
    SELECT 
           NEXT_DAY(action_date, 1) - 7 week
         , action_date             
         , COUNT(account_id) num_events
         , COUNT(DISTINCT account_id) num_unique_accounts
    FROM     actions
    GROUP BY action_date 
)      
SELECT events.*, 
      (SELECT COUNT(DISTINCT(account_id)) 
         FROM actions 
        WHERE action_date < events.week + 7) as num_unique_accounts_wtd
 FROM events
ORDER BY events.action_date

ご覧のとおり、イベント サブクエリの各行のすべての個別のaccount_idを (再) カウントするという考え方です。

于 2012-09-12T08:50:13.070 に答える
0

答えは、分析関数を変更して、次の形式の何かを含めることができるようにすることだったようです。

COUNT(DISTINCT ...) OVER (PARTITION BY ... ORDER BY ... RANGE BETWEEN ... AND ...) 

RANGE BETWEEN は式を許可するため、探しているものを取得するために PARTITION BY ウィンドウをさらにサブセット化できます。残念ながら、Oracle は

ORA-30487 DISTINCT functions and RATIO_TO_REPORT cannot have an ORDER BY

エラーなので使えません。

エラーをグーグルで調べた後、他の人が同じことを試みていることを発見し(ここここ)、リンク内で2つの答えが見つかりました.1つは実世界のデータに使用しました。

参考までに、元の投稿のモデルを使用したこの質問の回答は、次のような形式になります。

SELECT    action_date, COUNT(account_id) num_attempts, MAX(num_accounts) num_unique_accounts_wtd
FROM
(
    SELECT
        action_date
        , account_id
        , SUM(is_unique) OVER (PARTITION BY NEXT_DAY(action_date, 'Monday') - 7 ORDER BY action_date ASC, account_id ASC) num_accounts
    FROM
    (
        SELECT
            action_date
            , account_id
            , CASE
                WHEN LAG(account_id) OVER (PARTITION BY NEXT_DATE(action_date, 'Monday') - 7, account_id ORDER BY action_date ASC) = account_id 
                THEN 0
                ELSE 1
            END is_unique
            FROM
                actions
    )
)
GROUP BY  action_date

だからデータは

  1. 繰り返し、各口座番号の週について、それが一意であるかどうかを判断します
  2. 次に、毎週、最初にセットをアクション日付で並べ替え、次にaccount_idで並べ替え、現在の合計を作成します
  3. アクションの日付でグループ化し、現在までの最大週数を取得します
于 2012-09-12T16:41:54.927 に答える