2

私はこのようなテーブルを持っています:

SELECT * FROM orders;

 client_id | order_id | salesman_id | price
-----------+----------+-------------+-------
         1 |      167 |           1 |    65
         1 |      367 |           1 |    27
         2 |      401 |           1 |    29
         2 |      490 |           2 |    48
         3 |      199 |           1 |    68
         3 |      336 |           2 |    22
         3 |      443 |           1 |    84
         3 |      460 |           2 |    92

一意のセールスマンとクライアントのペアごとに、最も高額な販売ごとにorder_idの配列を見つけたいと思います。この場合、結果のテーブルが必要です。

 salesman_id |   order_id
-------------+----------------
           1 | {167, 401, 443}
           2 | {490, 460}

これまでのところ、クエリの概要があります。

SELECT salesman_id, max_client_salesman(order_id)
FROM orders
GROUP BY salesman_id;

ただし、集計関数max_client_salesmanの記述に問題があります。

postgresの集計関数と配列に関するオンラインドキュメントはごくわずかです。どんな助けでも大歓迎です。

4

2 に答える 2

2

標準SQL

ウィンドウ関数last_value()またはfirstvalue()とを組み合わせて、DISTINCTあたりの価格が最も高い注文を効率的に取得し、これを単純な集計関数(salesman_id, client_id)を使用して探している配列に集約します。array_agg()

SELECT salesman_id
      ,array_agg(max_order_id) AS most_expensive_orders_per_client
FROM  (
   SELECT DISTINCT
          salesman_id, client_id
         ,last_value(order_id) OVER (PARTITION BY salesman_id, client_id
                                     ORDER BY price
                                     ROWS BETWEEN UNBOUNDED PRECEDING
                                     AND UNBOUNDED FOLLOWING) AS max_order_id
   FROM   orders
   ) x
GROUP  BY salesman_id
ORDER  BY salesman_id;

戻り値:

 salesman_id |  most_expensive_orders_per_client
-------------+------------------------------------
           1 | {167, 401, 443}
           2 | {490, 460}

SQLフィドル。

あたりに複数の最高価格がある場合(salesman_id, client_id)、このクエリは、定義が不足しているため、任意に1つだけを選択します。 order_id

このソリューションでは、ウィンドウ関数がの前に適用されることを理解することが不可欠DISTINCTです。DISTINCTウィンドウ関数と組み合わせる方法:

の説明については、dba.SEのこの密接に関連する回答をROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING参照してください。

非標準のシンパーDISTINCT ON

PostgreSQLは、SQL標準の拡張機能としてを実装していますDISTINCT ON。これを使用すると、定義された列のセットに従って一意の行を非常に効果的に選択できます。
これよりも単純になったり速くなったりすることはありません。

SELECT salesman_id
      ,array_agg(order_id) AS most_expensive_orders_per_client
FROM  (
   SELECT DISTINCT ON (1, client_id)
          salesman_id, order_id
   FROM   orders
   ORDER  BY salesman_id, client_id, price DESC
   ) x
GROUP  BY 1
ORDER  BY 1;

SQLフィドル。

また、構文を短くするために位置パラメーターを使用します。詳細:

于 2013-02-06T02:28:08.380 に答える
0

array_aggPostgres関数と組み合わせて欲しいと思いますrow_number() が、クエリの説明は私には意味がありません。

以下は、クライアントとセールスマン、およびセールスマンによる最高価格の注文の注文リストを取得します。

select client_id, salesman_id, array_agg(order_id)
from (select o.*,
             row_number() over (partition by salesman_id order by price desc) as sseqnum,
             row_number() over (partition by client_id order by price desc) as cseqnum
      from orders o
     ) o
where sseqnum = 1
group by salesman_id, client_id

「各セールスマンとクライアントの最高価格の売上高」とはどういう意味かわかりません。おそらくあなたが望む:

where sseqnum = 1 or cseqnum = 1
于 2013-02-06T00:28:01.820 に答える