2

顧客 ID、日付、および整数を含む postgres テーブルがあります。昨年の日付を持つ各顧客 ID の上位 3 つのレコードの平均を見つける必要があります。以下の SQL を使用して、単一の ID でそれを行うことができます (id は顧客 ID、週末は日付、maxattached は整数です)。

1 つの注意点: 最大値は 1 か月ごとです。つまり、特定の月の最高値のみを調べてデータセットを作成しているため、日付から月を抽出しているのです。

SELECT 
  id,
  round(avg(max),0) 
FROM 
  (
   select 
     id,
     extract(month from weekending) as month,
     extract(year from weekending) as year,
     max(maxattached) as max 
   FROM 
     myTable 
   WHERE
     weekending >= now() - interval '1 year' AND 
     id=110070 group by id,month,year 
   ORDER BY
     max desc limit 3
   ) AS t 
GROUP BY id;

このクエリを拡張して、すべての ID とそれぞれの 1 つの平均値を含めるにはどうすればよいですか?

サンプルデータは次のとおりです。

ID     | MaxAttached | Weekending
110070 | 5           | 2011-11-10
110070 | 6           | 2011-11-17
110071 | 4           | 2011-11-10
110071 | 7           | 2011-11-17
110070 | 3           | 2011-12-01
110071 | 8           | 2011-12-01
110070 | 5           | 2012-01-01
110071 | 9           | 2012-01-01

したがって、このサンプル テーブルでは、次の結果が得られると予想されます。

ID     | MaxAttached

110070 | 5           
110071 | 8

これは、各 ID の特定の月における最高値の平均です (110070 の場合は 6、3、5、110071 の場合は 7、8、9)。

注: postgres バージョン 8.1.15

4

2 に答える 2

4

最初に -max(maxattached)すべての顧客と月について取得します。

SELECT id,
       max(maxattached) as max_att         
FROM myTable 
WHERE weekending >= now() - interval '1 year' 
GROUP BY id, date_trunc('month',weekending);

次へ - すべての顧客について、すべての値をランク付けします。

SELECT id,
       max_att,
       row_number() OVER (PARTITION BY id ORDER BY max_att DESC) as max_att_rank
FROM <previous select here>;

次へ - すべての顧客のトップ 3 を取得します。

SELECT id,
       max_att
FROM <previous select here>
WHERE max_att_rank <= 3;

次に -avgすべての顧客の値を取得します。

SELECT id,
       avg(max_att) as avg_att
FROM <previous select here>
GROUP BY id;

次に、すべてのクエリをまとめて、ケースに合わせて書き直して単純化します。

更新: これは、テスト データとクエリを含む SQLFiddle です: SQLFiddle

UPDATE2: 8.1 で動作するクエリは次のとおりです。

SELECT customer_id,
       (SELECT round(avg(max_att),0)
        FROM (SELECT max(maxattached) as max_att         
              FROM table1
              WHERE weekending >= now() - interval '2 year' 
                AND id = ct.customer_id
              GROUP BY date_trunc('month',weekending)
              ORDER BY max_att DESC
              LIMIT 3) sub 
        ) as avg_att
FROM customer_table ct;

アイデア - 最初のクエリを取得し、すべての顧客に対して実行します ( customer_table- すべての顧客に対して一意idのテーブル)。

このクエリの SQLFiddle は次のとおりです: SQLFiddle

バージョン 8.3 でのみテストされています (8.1 は SQLFiddle にするには古すぎます)。

于 2013-01-12T18:09:57.620 に答える
0

8.3 バージョン

8.3 は私がアクセスできる最も古いバージョンであるため、8.1 で動作することは保証できません。

一時テーブルを使用して、最高の 3 つのレコードを計算しています。

CREATE TABLE temp_highest_per_month as
   select 
     id,
     extract(month from weekending) as month,
     extract(year from weekending) as year,
     max(maxattached) as max_in_month,
     0 as priority
   FROM 
     myTable 
   WHERE
     weekending >= now() - interval '1 year' 
   group by id,month,year;

UPDATE temp_highest_per_month t
SET priority = 
 (select count(*) from temp_highest_per_month t2
  where t2.id = t.id and 
   (t.max_in_month < t2.max_in_month or
     (t.max_in_month= t2.max_in_month and
      t.year * 12 + t.month > t2.year * 12 + t.month)));

select id,round(avg(max_in_month),0)
from temp_highest_per_month
where priority <= 3
group by id;

年と月は優先順位の計算に含まれているため、2 つの月の最大値が同じ場合でも、それらは正しく番号付けに含まれます。

9.1 バージョン

Igor の回答に似ていますが、With 句を使用してステップを分割しました。

with highest_per_month as
  ( select 
     id,
     extract(month from weekending) as month,
     extract(year from weekending) as year,
     max(maxattached) as max_in_month
   FROM 
     myTable 
   WHERE
     weekending >= now() - interval '1 year' 
   group by id,month,year),
  prioritised as
  ( select id, month, year, max_in_month,
    row_number() over (partition by id, month, year
                       order by max_in_month desc)
    as priority
    from highest_per_month
   )
select id, round(avg(max_in_month),0)
from prioritised
where priority <= 3
group by id;
于 2013-01-12T18:34:15.353 に答える