我有一个表(在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
我想知道是否有更好的方法编写此查询?以及如何包含对数为零的日期类型?
实际上,有几种不同的类型,最长可达五年(1800个日期),dates_ranges
表中约有3万行(但它可能会显着增长)。
没有索引。准确地说,这是子查询的结果,但是我想将问题限制为一个问题,所以它更笼统。
2018-01-31
或者2018-01-30
或者2018-01-29
在它时,第1范围具有所有的人?
generate_series
是外部参数-它们不一定涵盖dates_ranges
表中的所有范围。关于第一个问题,我想我不理解-输入中的行dates_ranges
是独立的,我不想确定重叠。
(1,2018-01-01,2018-01-15)
并且(1,2018-01-20,2018-01-25)
在确定有多少个重叠日期时是否要考虑这一点?