Запуск складного запиту для кожної дати в діапазоні


9

У мене є таблиця замовлень

   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 .


2
Чи можете ви показати деякі приклади даних? Ці активні / неактивні та тимчасові речі не дуже зрозумілі після першого читання.
dezso

Так, незрозуміло. У вашому запиті знайдеться одне замовлення на кожного клієнта, і воно, схоже, не буде детермінованим. Якщо для клієнта є 2 або більше замовлень, з тим самим типом, яке з двох повернених буде довільним і змінюватиметься в залежності від виконання. Отже, у вас є або якісь обмеження на столі, які ви нам не сказали, або ваш запит невірний.
ypercubeᵀᴹ

Я оновив своє питання набагато більше деталей, і так, є обмеження в даних.
рекобата

Відповіді:


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

http://sqlfiddle.com/#!15/5a420/16/0

Я можу розробити більше, якщо щось не зрозуміло.


Це не стосується тимчасового замовлення / постійного замовлення, але це може бути зроблено після приєднання =)
перезавантажтеся

Це визначає той самий порядок, що і у вашому вікні запиту. Отже, для будь-якого (дата, client_id) він обрав би перший тип_порядку у зворотному алфавітному порядку.
Саймон Перепелиця

Внутрішнє з'єднання є ідеальним, а виділене виділення набагато простіше зрозуміти (і виконує приблизно так само добре), ніж вікно. З будь-якої іншої причини я не повинен використовувати функції вікон?
рекобата

1
Ось про це. Я думаю, що distinct onце навіть більш оптимізовано, ніж запит до вікна. До речі, я мушу зазначити, що це звичайна проблема "топ-групи" в SQL: stackoverflow.com/questions/3800551/…
Саймон Перепелиця,

Це чудове читання, я маю щось вивчити. Якщо у вас є якийсь час, у мене є розширена версія цього питання, в якій використовується те, що я дізнався тут. dba.stackexchange.com/questions/108767/… Я впевнений, що повернусь, щоб оновити його тим, що я дізнаюся за цим посиланням. І спасибі
рекобата

0

Напишіть функцію, яка приймає одну параметр як параметр і повертає список дат + ідентифікаторів, які мають замовлення.

Потім використовуйте Gene_series, як ви запропонували, і зателефонуйте до функції в межах дат.

Це загальна стратегія при роботі зі складними умовами в SQL.

Я включив деякий код нижче, але відповідь у SQL вище набагато простіше.

Ось функція:

create or replace function o( date) returns setof INT AS '
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 <= $1 and (end_date is null OR end_date >= $1)
) active_orders
WHERE id = active_order_id;
' LANGUAGE sql ;

І як це назвати:

select distinct d, o(d::date) 
from generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') as d;

SQLFiddle


2
Ви можете залишити цю відповідь якоюсь деталлю, зразком коду тощо. Як це є, ця відповідь може бути видалена, оскільки вона досить розпливчаста.
Макс Вернон

Чи зможете ви оновити мою загадку на прикладі? sqlfiddle.com/#!15/5a420/3/0
рекобат

Я оновив свою відповідь, щоб включити якийсь код, але відповідь вище простіший.
Дон Дрейк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.