次のようなテーブル(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 |
+-------+------------+----+
私は2つの解決策、との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
と1つあり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
このクエリを作成するためのより良い方法はあるのでしょうか?そして、カウント0の日付のペアを含める方法は?
実際には、いくつかの明確な種類があり、最長5年(1800日付)の期間と、dates_ranges
テーブルに約3万行あります(ただし、大幅に増加する可能性があります)。
インデックスはありません。私の場合、正確にはサブクエリの結果ですが、質問を1つの問題に限定したかったので、より一般的です。
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)
、あなたが持っているどのように多くの重複の日付を決定する際に考慮に入れていることをしたいですか?