2015-08-03 2 views
3

Я создаю систему управления подписками и вам нужно создать список предстоящей даты выставления счетов в течение следующих 2 лет. Я был в состоянии использовать generate_series, чтобы получить соответствующие даты, как например:Postgres generate_series, исключая диапазоны дат

SELECT i::DATE 
FROM generate_series('2015-08-01', '2017-08-01', '1 month'::INTERVAL) i 

Последний шаг мне нужно принять это исключить определенные диапазоны дат из расчета. Эти исключенные диапазоны дат могут быть любым диапазоном времени. Кроме того, они не должны учитываться во временном диапазоне для generate_series.

Например, у нас есть исключение диапазона дат от '2015-08-27' до '2015-09-03'. Полученные generate_series следует исключить дату, неделю из расчета, и в основном толчок весь будущий месяц биллинг даты за одну неделю до будущего:

2015-08-01 
2015-09-10 
2015-10-10 
2015-11-10 
2015-12-10 
+0

Удаленный ответ, не затрагивает действительно трудную часть. Исключение диапазонов легко. Жесткая часть - это корректировка повторяемого шаблона, добавление большего количества времени в конец для компенсации пропущенных интервалов времени, а затем корректировка повторяющихся дат. Вам понадобится рекурсивный CTE или процедура для этого, я думаю, так как строки, добавленные путем компенсации исключения в конце, сами могут быть исключены, поэтому мы должны затем расширить число строк для проверки ... –

+1

I также чувствуется, что ваш ежемесячный биллинг плохо сочетается с допуском исключений в течение нескольких дней или недель, потому что не каждый месяц имеет такое же количество дней.Вы можете подумать о выставлении счетов каждые 30 дней, а не каждый месяц. –

+1

Ваш пример кажется неправильным. Дата увеличивается на 9 дней, но интервал составляет всего 7 дней. –

ответ

0

Вам придется разделить вызов для создания серии для исключений. Некоторые вещи, как это:

  • Союз 3 запросы
  • Первого запрос тянет даты от начала до диапазона исключения из
  • Второго запроса тянет даты между диапазоным исключением до и дата окончания
  • Третьего запрос тянет дату когда ни одна из ваших серий не пересекается с диапазоном исключений

Примечание: Вам по-прежнему необходимо пройти через список исключений (если он у вас есть). Также этот запрос может быть не очень эффективным, поскольку такие сценарии могут быть лучше обработаны через функции или процедурный код.

1

Сначала необходимо создать временной ряд дат в течение следующих двух лет, EXCEPT ваши затемненные даты:

SELECT dt 
FROM generate_series('2015-08-01'::date, '2017-08-01'::date, interval '1 day') AS s(dt) 
EXCEPT 
SELECT dt 
FROM generate_series('2015-08-27'::date, '2015-09-03'::date, interval '1 day') as ex1(dt) 

Обратите внимание, что вы можете иметь столько EXCEPT пункты, как вам нужно. Для отдельных дней отключения (в отличие от диапазонов) вы можете использовать предложение VALUES вместо SELECT.

Затем окно в течение этого временного ряда, чтобы генерировать номера строк из почасовых дней:

SELECT row_number() OVER (ORDER BY dt) AS rn, dt 
FROM (<query above>) x 

Затем вы выбираете те дни, когда вы хотите, чтобы счет:

SELECT dt 
FROM (<query above>) y 
WHERE rn % 30 = 1; -- billing on the first day of the period 

(Этот последний запрос следующим советы Крейга биллинга на 30 дней)

Урожайность:

SELECT dt 
FROM (
    SELECT row_number() OVER (ORDER BY dt) AS rn, dt 
    FROM (
    SELECT dt 
    FROM generate_series('2015-08-01'::date, '2017-08-01'::date, interval '1 day') AS s(dt) 
    EXCEPT 
    SELECT dt 
    FROM generate_series('2015-08-27'::date, '2015-09-03'::date, interval '1 day') as ex1(dt) 
) x 
) y 
WHERE rn % 30 = 1;