У меня есть стол заказов
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
Данные имеют неперекрывающиеся постоянные заказы для client_id и иногда временный заказ, который переопределяет постоянный заказ на их start_date, когда они имеют совпадающий client_id. Существуют ограничения уровня приложения, которые не допускают перекрытия заказов одного типа.
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
Например, на 2015-07-18
клиенте 16 есть заказ № 20, поскольку он является активным заказом, потому что он отменяет постоянный заказ № 19. С некоторой суетой я нашел эффективный способ запрашивать идентификаторы активных заказов на дату.
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
Если вы запросите это 2015-07-18
в качестве заполнителей, вы получите
id
----
17
18
20
План запроса по этому запросу по сравнению с некоторыми другими моими идеями (такими как подзапросы, подсчитывающие количество временных заказов для клиента на дату) довольно мал, и я очень доволен этим. (дизайн стола, я не в восторге)
Теперь мне нужно найти все активные заказы для диапазона дат, объединенного с датами, в которые они активны. Например, с диапазоном дат 2015-07-18
до 2015-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
Порядок 20 переопределяет порядок 19, 2015-07-18
но не включен 2015-07-19
.
Я обнаружил, generate_series()
что могу сгенерировать диапазон дат, но я понятия не имею, как соединить это с этим, чтобы получить таблицу дат и идентификаторы заказов. Я предчувствую, что это взаимное объединение, но я не могу понять, как заставить это работать в таких условиях.
Спасибо
ОБНОВЛЕНИЕ Добавлена скрипта sql .
источник
Ответы:
Я бы использовал
select distinct on
вместо оконной функции, а затем просто присоединиться к дням.http://sqlfiddle.com/#!15/5a420/16/0
Я могу уточнить, если что-то не понятно.
источник
distinct on
это даже более оптимизировано, чем запрос окна. Кстати, я должен упомянуть, что это распространенная проблема «top-in-group» в SQL: stackoverflow.com/questions/3800551/…Напишите функцию, которая принимает одну дату в качестве параметра и возвращает список дат + идентификаторы, которые имеют порядок.
Затем используйте generate_series, как вы предложили, и вызывайте функцию в диапазоне дат.
Это общая стратегия при работе со сложными условиями в SQL.
Я включил немного кода ниже, но ответ на SQL выше намного проще.
Вот функция:
И как это назвать:
SQLFiddle
источник