У меня есть таблица (в PostgreSQL 9.4), которая выглядит следующим образом:
CREATE TABLE dates_ranges (kind int, start_date date, end_date date);
INSERT INTO dates_ranges VALUES
(1, '2018-01-01', '2018-01-31'),
(1, '2018-01-01', '2018-01-05'),
(1, '2018-01-03', '2018-01-06'),
(2, '2018-01-01', '2018-01-01'),
(2, '2018-01-01', '2018-01-02'),
(3, '2018-01-02', '2018-01-08'),
(3, '2018-01-05', '2018-01-10');
Теперь я хочу подсчитать для заданных дат и для каждого вида, во сколько строк dates_ranges
попадает каждая дата. Нули могут быть опущены.
Желаемый результат:
+-------+------------+----+
| kind | as_of_date | n |
+-------+------------+----+
| 1 | 2018-01-01 | 2 |
| 1 | 2018-01-02 | 2 |
| 1 | 2018-01-03 | 3 |
| 2 | 2018-01-01 | 2 |
| 2 | 2018-01-02 | 1 |
| 3 | 2018-01-02 | 1 |
| 3 | 2018-01-03 | 1 |
+-------+------------+----+
Я придумал два решения, одно с LEFT JOIN
иGROUP BY
SELECT
kind, as_of_date, COUNT(*) n
FROM
(SELECT d::date AS as_of_date FROM generate_series('2018-01-01'::timestamp, '2018-01-03'::timestamp, '1 day') d) dates
LEFT JOIN
dates_ranges ON dates.as_of_date BETWEEN start_date AND end_date
GROUP BY 1,2 ORDER BY 1,2
и один с LATERAL
, который немного быстрее:
SELECT
kind, as_of_date, n
FROM
(SELECT d::date AS as_of_date FROM generate_series('2018-01-01'::timestamp, '2018-01-03'::timestamp, '1 day') d) dates,
LATERAL
(SELECT kind, COUNT(*) AS n FROM dates_ranges WHERE dates.as_of_date BETWEEN start_date AND end_date GROUP BY kind) ss
ORDER BY kind, as_of_date
Мне интересно, есть ли лучший способ написать этот запрос? А как включить пары date-kind с 0 count?
В действительности существует несколько различных видов, период до пяти лет (1800 дат) и ~ 30 тыс. Строк в dates_ranges
таблице (но это может значительно возрасти).
Там нет индексов. Если быть точным, в моем случае это результат подзапроса, но я хотел ограничить вопрос одной проблемой, поэтому она носит более общий характер.
2018-01-31
или 2018-01-30
или 2018-01-29
в ней , когда первый диапазон имеет все из них?
generate_series
являются внешними параметрами - они не обязательно охватывают все диапазоны в dates_ranges
таблице. Что касается первого вопроса, я полагаю, что я его не понимаю - строки в нем dates_ranges
независимы, я не хочу определять перекрытие.
(1,2018-01-01,2018-01-15)
и(1,2018-01-20,2018-01-25)
вы хотите принять это во внимание при определении количества перекрывающихся дат?