【问题标题】:How do I obtain the value from first the row of a grouped part?如何从分组部分的第一行获取值?
【发布时间】:2012-03-24 11:37:28
【问题描述】:

我有产品、发票和客户。客户发票上是不含税售价的产品。我需要为每个客户(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

【问题讨论】:

  • 您当前的查询是如何失败的?

标签: sql postgresql


【解决方案1】:

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)

【讨论】:

    【解决方案2】:

    我认为,要从第一张发票中获取售价,您需要有关 sale_date 的信息或您未在请求中解释的有效标准。

    实现这一结果的方法有很多种,但我更喜欢的方法是仅基于聚合函数。以下示例使用postges,但其他数据库也可能为您提供相同的功能。

    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=#
    

    【讨论】:

      猜你喜欢
      • 2021-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多