如何从分组部件的第一行获取值?

时间:2012-03-24 11:37:29

标签: sql postgresql

我有产品,发票和客户。在客户发票上是一个没有税的销售价格的产品。我需要为每个客户报告product_id =45的最低销售价格以及第一张发票的销售价格。

我可以将除最后一个条件之外的所有内容分组。我知道可以使用subselect完成,但我想避免使用它们。

简化的数据库结构:

table clients
-clent_id serial

table products
-product_id serial
-name text

table invoices
-invoice_id serial
-client_id int

table invoices_rows
-invoice_row_id serial
-invoice_id int
-product_id int
-price double precision

2 个答案:

答案 0 :(得分:3)

window functions与DISTINCT结合使用,同时获得最低价和第一个价格(不按要求进行子选择):

SELECT DISTINCT ON (i.client_id)
       i.client_id
     , min(ir.price) OVER (PARTITION BY i.client_id) AS min_price
     , first_value(ir.price) OVER (PARTITION BY i.client_id
                                   ORDER BY ir.invoice_id) AS first_price
FROM   invoices_rows ir
JOIN   invoices i USING (client_id)
WHERE  ir.product_id = 45;

应用DISTINCT ON(client_id),每client_id只获取一行。 DISTINCT在窗口函数之后应用,而GROUP BY将在之前应用。

我假设“第一张发票”可以解释为“最低invoice_id”。 您是否需要每个客户的“最低售价”?或者产品的整体最低价格?我现在改为“per client_id”。似乎更有可能。


如果您不介意子选择或CTE,这可能表现最佳:

WITH x AS (
    SELECT i.client_id
         , min(ir.price) AS min_price
         , min(ir.invoice_id) AS invoice_id
    FROM   invoices_rows ir
    JOIN   invoices i USING (client_id)
    WHERE  ir.product_id = 45
    )
SELECT x.*, ir.price AS first_price
FROM   x
JOIN   invoices_rows ir USING (invoice_id)

答案 1 :(得分:0)

我认为,要从第一张发票中获得售价,您需要有关sale_date的信息或您未在请求中说明的有效条件。

有不同的方法可以实现这个结果,但我喜欢的方法只基于聚合函数。以下示例使用postges,但其他DB也可以为您提供相同的功能。

postgres=# select *
postgres-# from prices_products;
 product_name | customer_name | price | sell_date
--------------+---------------+-------+------------
 knife        | mark          |   100 | 2011-01-20
 book         | cris          |    20 | 2011-05-12
 book         | mark          |    25 | 2010-09-30
 book         | cris          |    30 | 2012-02-15
(4 rows)


postgres=#
postgres=# select product_name, customer_name,m as maximum, arr[1] as first_date_val
postgres-# from (
postgres(#              select product_name, customer_name, max(price) as m, array_agg(price order by sell_date) as arr
postgres(#              from prices_products
postgres(#              group by product_name, customer_name
postgres(#      ) a;
 product_name | customer_name | maximum | first_date_val
--------------+---------------+---------+----------------
 book         | cris          |      30 |             20
 book         | mark          |      25 |             25
 knife        | mark          |     100 |            100
(3 rows)


postgres=#