我有一张订单表
Column | Type | Modifiers
------------+-----------------------------+-----------------------------------------------------
id | integer | not null default nextval('orders_id_seq'::regclass)
client_id | integer | not null
start_date | date | not null
end_date | date |
order_type | character varying | not null
Run Code Online (Sandbox Code Playgroud)
数据具有针对 client_id 的非重叠常规订单,并且偶尔会出现临时订单,当它们具有匹配的 client_id 时,会覆盖其 start_date 的常规订单。存在应用程序级别的限制,以防止相同类型的订单重叠。
id | client_id | start_date | end_date | order_type
----+-----------+------------+------------+------------
17 | 11 | 2014-02-05 | | standing
18 | 15 | 2014-07-16 | 2015-07-19 | standing
19 | 16 | 2015-04-01 | | standing
20 | 16 | 2015-07-18 | 2015-07-18 | temporary
Run Code Online (Sandbox Code Playgroud)
例如,在2015-07-18
客户端 16 上,订单 #20 是活动订单,因为它覆盖了常规订单 #19。经过一番大惊小怪,我找到了一种有效的方式来查询某个日期的活动订单 ID。
SELECT id from (
SELECT
id,
first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
FROM orders
WHERE start_date <= ? and (end_date is null OR end_date >= ?)
) active_orders
WHERE id = active_order_id
Run Code Online (Sandbox Code Playgroud)
如果你用2015-07-18
占位符查询它,你会得到
id
----
17
18
20
Run Code Online (Sandbox Code Playgroud)
与我的其他一些想法(例如计算某个日期客户的临时订单数量的子查询)相比,此查询的查询计划非常小,我对此非常满意。(桌子的设计,我不兴奋)
现在,我需要找到一个日期范围内的所有活动订单,这些订单与它们的活动日期相连。例如,日期范围为2015-07-18
to2015-07-19
我想要以下结果。
active_date | id
------------+----
2015-07-18 | 17
2015-07-18 | 18
2015-07-18 | 20
2015-07-19 | 17
2015-07-19 | 18
2015-07-19 | 19
Run Code Online (Sandbox Code Playgroud)
订单 20 覆盖订单 19,2015-07-18
但不覆盖2015-07-19
。
我发现generate_series()
我可以生成一系列日期,但我不知道如何将其与此结合以获取日期表和订单 ID。我的预感是交叉连接,但我不知道如何在这种情况下使其工作。
谢谢
更新 添加了一个sql 小提琴。
小智 5
我会用select distinct on
而不是窗口函数,然后就加入日子。
select
distinct on (date, client_id) date,
id
from orders
inner join generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') date
on start_date <= date and (end_date is null or date <= end_date)
order by date, client_id, order_type desc
Run Code Online (Sandbox Code Playgroud)
http://sqlfiddle.com/#!15/5a420/16/0
如果有什么不清楚的,我可以详细说明。