我正在处理许多不同产品的历史价格数据。
我有一张表products
,列出了所有带有名称,描述等的产品,用uuid标识它们。然后还有另一个表history
,用于存储每个产品的每次价格变化。价格可能(通常会)每天变化很多次。
现在我想计算每个产品在特定时间点的价格,比如2015年3月14日中午12点。我怎样才能在SQL中执行此操作?
我能够为一种产品做到这一点:
SELECT product_id, price, date
FROM history
WHERE product_id = 'aa6d9976-e9ae-4478-486e-097e86c1e5fe'
AND (date-'2015-03-14 12:00:00+02') < interval '1 second'
ORDER BY diff DESC LIMIT 1
-> aa6d9976-e9ae-4478-486e-097e86c1e5fe 109 2015-03-14 11:55:00+01
但我希望一组查询中的所有产品。我的想法是获取所有产品并将该表与历史记录联系起来,为每个产品选择合适的价格,但我对后者失败了:
SELECT products.product_id, name, price, date
FROM products
LEFT JOIN history ON products.product_id = history.product_id
WHERE date "is the greatest value that is still somewhat smaller than" '2015-03-14 12:00:00+01'
你如何正确地写下我试图用引号表达的内容?
我使用PostgreSQL(虽然我之前主要使用过MySQL)。这些表分别约为1.5万(产品)和5000万(历史)行。
如果您喜欢某些示例数据:
PRODUCTS
product_id name
aa6d9976-e9ae-4478-486e-097e86c1e5fe One
8da97d50-540e-4fdb-d032-7f443a9869a0 Two
b51654ea-6190-4ed2-5e23-7075ffd3b472 Three
HISTORY
id product_id price date
1 aa6d9976-e9ae-4478-486e-097e86c1e5fe 100 2015-03-14 09:30:00+01
2 aa6d9976-e9ae-4478-486e-097e86c1e5fe 110 2015-03-14 10:48:00+01
3 b51654ea-6190-4ed2-5e23-7075ffd3b472 9 2015-03-14 11:01:00+01
4 8da97d50-540e-4fdb-d032-7f443a9869a0 49 2015-03-14 11:27:00+01
5 aa6d9976-e9ae-4478-486e-097e86c1e5fe 109 2015-03-14 11:55:00+01
6 b51654ea-6190-4ed2-5e23-7075ffd3b472 8 2015-03-14 13:59:00+01
7 aa6d9976-e9ae-4478-486e-097e86c1e5fe 110 2015-03-14 16:10:00+01
8 8da97d50-540e-4fdb-d032-7f443a9869a0 48 2015-03-14 19:34:00+01
9 8da97d50-540e-4fdb-d032-7f443a9869a0 49 2015-03-14 23:30:00+01
10 aa6d9976-e9ae-4478-486e-097e86c1e5fe 103 2015-03-14 23:33:00+01
DESIRED OUTPUT
id name price date
aa6d9976-e9ae-4478-486e-097e86c1e5fe One 109 2015-03-14 11:55:00+01
8da97d50-540e-4fdb-d032-7f443a9869a0 Two 49 2015-03-14 11:27:00+01
b51654ea-6190-4ed2-5e23-7075ffd3b472 Three 9 2015-03-14 11:01:00+01
答案 0 :(得分:0)
首先编写查询以查找小于查询每个产品的日期的最大日期。这看起来像这样:
select product_id, MAX(date) date
from history
where date < '3/14/2015 12:00:00'
group by product_id
然后,您可以使用products
和history
表加入该子查询,以获得所需的结果:
select products.*, history.price, history.date
from products
left join
(
select product_id, MAX(date) date
from history
where date < '3/14/2015 12:00:00'
group by product_id
) PriceDates
on products.product_id = PriceDates.product_id
join history
on PriceDates.product_id = history.product_id
and PriceDates.date = history.date
答案 1 :(得分:0)
使用窗口函数lead()查找给定product_id
的 next 对应记录(顺便说一句:我将date
重命名为zdate
。{{ 1}}是列的错误名称,因为它是数据类型的名称)
date
{product_id,zdate}上的索引可能会有所帮助;-)
结果:
SELECT h0.*
FROM history h0
JOIN (
SELECT id
, zdate AS start_date
, lead(zdate, 1, 'infinity' ) OVER (PARTITION BY product_id
ORDER BY zdate) AS end_date
FROM history
) h1 ON h0.id = h1.id
AND h1.start_date <= '2015-03-14 12:00:00+01'
AND h1.end_date > '2015-03-14 12:00:00+01'
;