Sql 获取具有每月创建日期周期的记录
我想抓取所有已创建的记录ℕ 一个月前,就在同一个小时。(记录的年龄应为ℕ 月、0天、0小时) ℕ = {1,2,…} 例如,如果Sql 获取具有每月创建日期周期的记录,sql,postgresql,Sql,Postgresql,我想抓取所有已创建的记录ℕ 一个月前,就在同一个小时。(记录的年龄应为ℕ 月、0天、0小时) ℕ = {1,2,…} 例如,如果now()是2016-11-15 13:15:00,则任何创建日期如下的记录都将被返回 2010-11-15 13:15:00 -- different year 2016-02-15 13:15:00 -- different month 2016-11-15 13:46:23 -- different minute/seconds 2010-11-15 13:
now()
是2016-11-15 13:15:00
,则任何创建日期如下的记录都将被返回
2010-11-15 13:15:00 -- different year
2016-02-15 13:15:00 -- different month
2016-11-15 13:46:23 -- different minute/seconds
2010-11-15 13:46:23 -- different year, month, minute and sec
我能想到的最好的简单查询是:
SELECT *
FROM mytable
WHERE extract(day from age(now(), created_date)) = 0 -- same day any month ago
AND extract(hour from age(now(), created_date)) = 0; -- same hour
但问题是,有些特定的日子将被排除在查询之外。比如什么时候
created_date=2016-01-31 13:00:00
now() is 2016-02-28 13:00:00
在这种情况下,记录的有效期为28天
,而不是1个月;根据Postgresql中的age
函数。
因此,无论是在2月底还是3月1日,它都不会被取走
任何关于如何以最简单的方式解决这个问题的想法都值得赞赏
以下是一些可用于验证的测试数据:
create table mytable (created_date timestamp, expected_records int);
truncate mytable;
insert into mytable (created_date, expected_records) values
('2013-01-11 13:22:33', 2),
('2014-02-11 13:58:22', 2),
('2015-03-21 13:22:00', 1),
('2013-02-28 13:11:00', 5),
('2017-02-28 13:22:00', 5),
('2016-03-31 13:22:00', 5),
('2015-04-30 13:22:00', 5),
('2014-05-31 13:22:00', 5),
('2014-05-31 12:22:00', 1);
最终的SELECT查询可以在这些TIMSTAMP中的任何一个上执行,但返回的行数应与预期的\u记录
状态相同。
您还可以使用
'some date':timestamp
而不是now()来伪造时间。您可以通过获得第一个月的一天(1天)来解决问题:
示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
加入示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
您还可以使用参数将其包装到函数中,如:
t=# create or replace function so45(_ts timestamp) returns table (lastday timestamp) as
$$
declare
_start timestamp;
_stop timestamp;
begin
select date_trunc('year', _ts) + (_ts)::time +concat(extract(day from _ts),' days')::interval into _start;
select date_trunc('year', _ts) + (_ts)::time +concat(extract(day from _ts),' days')::interval + '12 month'::interval into _stop;
return query with ts as (
select
generate_series(_start,_stop,'1 month'::interval)
- '1 day'::interval
lastday
)
select * from ts order by 1;
end;
$$ language plpgsql
;
CREATE FUNCTION
加入示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
您可以通过获得第一个月的第一天(1天)来解决此问题: 示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
加入示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
您还可以使用参数将其包装到函数中,如:
t=# create or replace function so45(_ts timestamp) returns table (lastday timestamp) as
$$
declare
_start timestamp;
_stop timestamp;
begin
select date_trunc('year', _ts) + (_ts)::time +concat(extract(day from _ts),' days')::interval into _start;
select date_trunc('year', _ts) + (_ts)::time +concat(extract(day from _ts),' days')::interval + '12 month'::interval into _stop;
return query with ts as (
select
generate_series(_start,_stop,'1 month'::interval)
- '1 day'::interval
lastday
)
select * from ts order by 1;
end;
$$ language plpgsql
;
CREATE FUNCTION
加入示例:
t=# create table so42(t timestamp);
CREATE TABLE
t=# insert into so42 select '2016-05-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-10-31 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-02-29 13:00:00';
INSERT 0 1
t=# insert into so42 select '2016-01-21 13:00:00';
INSERT 0 1
t=# with ts as (
select
generate_series('2016-01-01 13:00:00'::timestamp,'2016-12-01'::date,'1 month'::interval)
- '1 day'::interval
lastday
)
select t
from so42
join ts on ts.lastday = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-31 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-02-29 13:00:00
2016-05-31 13:00:00
2016-10-31 13:00:00
(3 rows)
t=# with ts as (select so45('2016-03-21 13:00:00'))
select t
from so42
join ts on ts.so45 = t
;
t
---------------------
2016-01-21 13:00:00
(1 row)
请尝试以下代码段,该代码段已经过测试并确认有效
SELECT *
FROM mytable
WHERE EXTRACT( HOUR FROM NOW() ) = EXTRACT( HOUR FROM created_date )
AND ( ( EXTRACT( DAY FROM NOW() ) = EXTRACT( DAY FROM created_date ) ) OR
( EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() ) AND
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() ) ) );
以下代码测试两个日期是否具有相同的天数,而不管其中一个日期是否为月末。在这种情况下,不需要对日期进行进一步测试
EXTRACT( DAY FROM NOW() ) = EXTRACT( DAY FROM created_date )
下面的代码测试NOW()
是否在月末
EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() )
以下代码测试created\u date
的天数值是否大于NOW()
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() )
因此,如果NOW()
的结束日期的值不大于created\u date
的日值,则可以将其视为等效(因此以下代码),例如NOW()
的日期=2017-02-28与created\u date
的2017-01-31或NOW()
的日期=2017-04-30与创建日期
的2017-12-31等
EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() ) AND
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() )
如果您有任何问题或意见,请发表相应的意见。请尝试以下代码段,该代码段已经过测试并确认有效
SELECT *
FROM mytable
WHERE EXTRACT( HOUR FROM NOW() ) = EXTRACT( HOUR FROM created_date )
AND ( ( EXTRACT( DAY FROM NOW() ) = EXTRACT( DAY FROM created_date ) ) OR
( EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() ) AND
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() ) ) );
以下代码测试两个日期是否具有相同的天数,而不管其中一个日期是否为月末。在这种情况下,不需要对日期进行进一步测试
EXTRACT( DAY FROM NOW() ) = EXTRACT( DAY FROM created_date )
下面的代码测试NOW()
是否在月末
EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() )
以下代码测试created\u date
的天数值是否大于NOW()
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() )
因此,如果NOW()
的结束日期的值不大于created\u date
的日值,则可以将其视为等效(因此以下代码),例如NOW()
的日期=2017-02-28与created\u date
的2017-01-31或NOW()
的日期=2017-04-30与创建日期
的2017-12-31等
EXTRACT( DAY FROM DATE_TRUNC( 'MONTH', NOW() ) + INTERVAL '1 MONTH - 1 DAY' ) = EXTRACT( DAY FROM NOW() ) AND
EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() )
如果您有任何问题或意见,请发表相应的意见。首先,让我们试着更好地了解您的需求。您需要所有记录,其时间戳列(
created\u date
)和当前时间(now()
)具有以下关系:
- 具有完全相同的小时数
和- 正好在同一天
或
有一个日期,它大于created\u date
的日期now()
但仅当
在当月的最后一天时now()
- 正好在同一天
选择*
从mytable
其中EXTRACT(从创建日期算起的小时)=EXTRACT(从现在算起的小时())
和(提取(从创建日期算起的日期)=提取(从现在算起的日期())
或案例
提取时(从当前日期算起的月份+1)提取时(从当前日期算起的月份)
然后提取(从创建日期算起的日期)>提取(从现在算起的日期())
否则错误
(完)
注意:如果您想为您的解决方案绑定
时间戳
s(不实际使用now()
¤t_date
函数),则使用提取时(月自?+间隔“1天”)>提取(月自?
测试绑定的时间戳是否为其月份的最后一天。首先,让我们试着更好地理解您的需求。您需要所有记录,其时间戳列(created\u date
)和当前时间(now()
)具有以下关系:
- 具有完全相同的小时数
和- 正好在同一天
或
有一个日期,它大于created\u date
的日期now()
但仅当
在当月的最后一天时now()
- 正好在同一天
选择*
从mytable
其中EXTRACT(从创建日期算起的小时)=EXTRACT(从现在算起的小时())
和(提取(从创建日期算起的日期)=提取(从现在算起的日期())
或案例
提取时(从当前日期算起的月份+1)提取时(从当前日期算起的月份)
然后提取(从创建日期算起的日期)>提取(从现在算起的日期())
否则错误
(完)
注意:如果要为解决方案绑定时间戳
s(实际上不使用now()
&当前日期
函数),则在提取时使用(从+