我一直在努力工作几个小时而没有运气而且已经撞墙了。我的数据如下:
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个。
答案 0 :(得分:3)
有一些样本行(应在问题中提供):
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
;
使用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;
没有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<>小提琴here
SQL Fiddle.
您正在寻找两个日期之间的完整日历月。
这些查询以升序或降序的方式处理任何日期或时间戳,并且应该表现良好。
WHERE
子句是可选的,因为generate_series()
如果开始>则不返回任何行。结束。但是,先验地排除空范围应该快一点。
施放到timestamp
使其更清洁,更快。理由:
答案 1 :(得分:0)
AFAIK你可以在postgresql中简单地减去/添加日期
'2001-06-27 14:43:21'::DATETIME - '2001-06-27 14:33:21'::DATETIME = '00:10:00'::INTERVAL
因此,在您的情况下,请求部分应该看起来像
DATE_PART('month', Date1::datetime - Date2::datetime) as "MonthInterval"
答案 2 :(得分:0)
年龄(timestamp1,timestamp2)=>返回间隔
我们尝试从间隔中提取年份和月份并相应地添加它们。
选择提取物(年龄(timestamp1,timestamp2))* 12 +提取物(月份来自 年龄(timestamp1,timestamp2))