我已经为此工作了几个小时,但运气不佳,结果碰壁了。我的数据如下所示:
Date1 Date2
2012-05-06 2012-05-05
2012-03-20 2012-01-05
我想做的是将两个日期之间每个月的计数加 1。所以我的输出理想情况下是这样的:
Year Month Sum
2012 2 1
换句话说,它应该检查两个日期之间是否有“空”月份,并将它们加 1。
这是我到目前为止编写的代码。它基本上会计算两个日期之间的月数,并将它们分组为月和年。
SELECT
EXTRACT(YEAR FROM Date2::date) as "Year",
EXTRACT(MONTH FROM Date2::date) as "Month",
SUM(DATE_PART('year', Date1::date) - DATE_PART('year', Date2::date)) * 12 +
(DATE_PART('month', Date1::date) - DATE_PART('month', Date2::date))
FROM
test
GROUP BY
"Year",
"Month",
ORDER BY
"Year" DESC,
"Month" DESC;
这就是我卡住的地方 - 我不知道如何为每个“空白”月份实际加 1。
最佳答案
测试设置
带有一些示例行(应在问题中提供):
CREATE TABLE test (
test_id serial PRIMARY KEY
, date1 date NOT NULL
, date2 date NOT NULL
);
INSERT INTO test(date1, date2)
VALUES
('2012-03-20', '2012-01-05') -- 2012-02 lies in between
, ('2012-01-20', '2012-03-05') -- 2012-02 (reversed)
, ('2012-05-06', '2012-05-05') -- nothing
, ('2012-05-01', '2012-06-30') -- still nothing
, ('2012-08-20', '2012-11-05') -- 2012-09 - 2012-10
, ('2012-11-20', '2013-03-05') -- 2012-12 - 2013-02
;
Postgres 9.3 或更新版本
使用LATERAL
连接:
SELECT to_char(mon, 'YYYY') AS year
, to_char(mon, 'MM') AS month
, count(*) AS ct
FROM (
SELECT date_trunc('mon', least(date1, date2)::timestamp) + interval '1 mon' AS d1
, date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
FROM test
) sub1
, generate_series(d1, d2, interval '1 month') mon -- implicit CROSS JOIN LATERAL
WHERE d2 >= d1 -- exclude ranges without gap right away
GROUP BY mon
ORDER BY mon;
Postgres 9.2 或更早版本
还没有 LATERAL
。改用子查询:
SELECT to_char(mon, 'YYYY') AS year
, to_char(mon, 'MM') AS month
, count(*) AS ct
FROM (
SELECT generate_series(d1, d2, interval '1 month') AS mon
FROM (
SELECT date_trunc('mon', least(date1, date2)::timestamp) + interval '1 mon' AS d1
, date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
FROM test
) sub1
WHERE d2 >= d1 -- exclude ranges without gap right away
) sub2
GROUP BY mon
ORDER BY mon;
结果
year | month | ct
------+-------+----
2012 | 2 | 2
2012 | 9 | 1
2012 | 10 | 1
2012 | 12 | 1
2013 | 1 | 1
2013 | 2 | 1
db<> fiddle here
SQL Fiddle.
说明
您要查找两个日期之间完整 个日历月。
这些查询适用于按升序或降序排列的任何日期或时间戳,并且应该表现良好。
WHERE
子句是可选的,因为 generate_series()
如果开始 > 结束,则不返回任何行。但是先验地排除空范围应该会更快一些。
转换为 timestamp
使其更简洁、更快速。理由:
关于sql - 计算两个日期之间的完整月份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11673136/