假设你有两张桌子:
订单
order_id , ....
1, ...
2, ...
每个订单都有一个'州历史'。它存储在历史表中:
serial, date, order_id , order_state
10, 2012-01-01, 1, 'INIT'
11, 2012-01-02, 2, 'INIT'
12, 2012-02-03, 1, 'COMPLETED'
13, 2012-02-04, 1, 'DISPATCHED'
14, 2012-02-05, 2, 'COMPLETED'
15, 2012-02-06, 2, 'DISPATCHED'
现在我想在过去的任何特定时刻知道我所有订单的状态。例如,我想知道2012-02-05的订单状态:
order_id, order_state, state_date
1 , 'DISPATCHED' , 2012-02-04
2, 'COMPLETED' , 2012-02-05
(state_date列是可选的。)
有没有办法编写一个查询来执行更有效而不是循环执行订单并在应用程序代码中获取其“给定日期的状态”?
我已经用Postgresql中的rank()WINDOW函数完成了这一点,但是我不太高兴它必须获取所有历史记录(在给定日期之前)只是为了选择等级1之一。在我看来,这并不比在应用程序代码中做得更好。
SELECT * FROM ( SELECT o.order_id,
h.order_state,
h.state_date,
rank() ON (PARTITION BY order_id ORDER BY h.serial DESC)
AS hrank
FROM order o, history h
WHERE
h.order_id = o.order_id AND
h.date < given_date
) AS rh
WHERE
rh.hrank = 1;
我真正想要的是我的分区定义中的某种LIMIT 1,但我不知道它是否可能。
答案 0 :(得分:2)
select distinct on (o.order_id) o.order_id, h.order_state, h.date
from
orders o
inner join
history h on h.order_id = o.order_id
where
h.date <= '2012-02-05'
order by o.order_id, h.date desc
distinct on
将根据声明的顺序返回第一个。在这种情况下是最近的日期。
答案 1 :(得分:1)
这可能会更快:
SELECT o.order_id,
h.order_state,
h.state_date,
FROM "order" o
JOIN history h ON h.order_id = o.order_id
WHERE h.order_date = (select max(h2.order_date)
from history h2
where h2.order_id = h.order_id
and h2.order_date <= date '2012-02-05');
(请注意,订单和历史记录之间的联接在这里并不是必需的,但我假设您的示例查询只是您真正想要的一部分)
答案 2 :(得分:0)
NOT EXISTS()救援:
SELECT o.order_id
-- h.zserial -- you might want to see this as well
, h.order_state
, h.state_date
FROM zorder o
JOIN history h ON h.order_id = o.order_id
-- You probably don't need this date comparison,
-- ,since it is already in the subquery
WHERE h.zdate < given_date
AND NOT EXISTS (
SELECT * FROM history nx
WHERE nx.order_id = o.order_id
AND nx.zdate < given_date
AND nx.zserial > h.zserial
);
注意:我将列名更改为不会与关键字冲突的名称。