postgresql SQL历史更改

idv4meu8  于 2023-04-05  发布在  PostgreSQL
关注(0)|答案(2)|浏览(106)

我希望建立一个应用程序,跟踪随着时间的推移某些亚马逊产品的价格变化。我想出了以下表格:

product

| ID | Name        |
| 1  | iPhone case |
| 2  | Wallet      | 

product_price

| ID | product | price | date |
| 1  |    1    | 12.99 | 2023-03-04 |
| 1  |    2    | 10.99 | 2023-03-02 |
| 1  |    1    | 9.99  | 2023-03-01 |

但是,我现在如何编写一个SQL查询来检索我所有的产品及其最新价格呢?
另一个我可以想到的解决方案是在product表中添加另一列:

| ID | name        | latest_price |
| 1  | iPhone case | 1            ]
| 2  | Wallet      | NULL         |

这样我就可以很容易地编写一个查询来获取产品及其最新价格。缺点是每当价格发生变化时,我也需要更新这个列。
有什么最佳实践吗?假设这看起来不像是一个新问题。

sr4lhrrt

sr4lhrrt1#

在Postgres中使用distinct on ()非常有效:

select distinct on (product) pp.*
from product_price pp
order by product, date desc;

这可以在连接中使用:

select p.*, pp.price as latest_price
from product p
  join (
    select distinct on (product) *
    from product_price pp
    order by product, date desc
  ) pp on pp.product = p.id

另一种选择是使用横向连接,有时更快:

select p.*, pp.price as latest_price
from product p
  join lateral (
    select *
    from product_price pp
    where pp.product = p.id
    order by pp.date desc
    limit 1
  ) pp on true

在任何情况下,product_price (product, date desc)上的索引都会加快这些查询的速度。
一种不同的建模方法是使用daterange来定义价格有效的时间。这在更新时有点复杂,因为在添加新价格之前必须关闭“最后一个”范围。但查询起来更灵活(甚至可能更快):

create table product_price 
(
  product int not null references product, 
  price numeric, 
  valid_during daterange,
  constraint unique_price_range 
     exclude using gist(product with =, valid_during with &&)
);

排除约束将防止单个产品的范围重叠。
然后,您可以使用以下命令查询“最新价格”(=“今天”的价格):

select *
from product_price
where valid_during @> current_date;

但这也使得查找任何日期的价格变得非常容易(例如,订购产品的日期):

select *
from product_price
where valid_during @> date '2023-03-18';

如果只存储开始日期,则运行该查询的开销要大得多。

qnzebej0

qnzebej02#

SELECT X.PRODUCT,X.PRICE,X.DATE 
 FROM
 ( 
   SELECT P.PRODUCT,P.PRICE,P.DATE,
   ROW_NUMBER()OVER(PARTITION BY P.PRODUCT ORDER BY P.DATE DESC,P.ID DESC)AS XCOL
   FROM product_price AS P
 ) AS X WHERE X.XCOL=1

要获得最新的价格,您可以使用查询像上面

相关问题