获取具有每月创建日期的记录

时间:2017-04-03 07:23:02

标签: sql postgresql

我想抓住ℕ月前创建的所有记录,完全相同的时间。 (记录年龄应仅为ℕ月,0天,0小时)

ℕ= {1,2,...}

例如,如果now()2016-11-15 13:15:00,则预计会返回任何具有以下create_date的记录。

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 days而不是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上执行,但应返回与expected_records个状态相同的行数。 此外,您可以使用'some date'::timestamp代替now()伪造时间。

3 个答案:

答案 0 :(得分:1)

您可以通过获取第一个月 - (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=# 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=# 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 :(得分:1)

请尝试以下代码段,该段经过测试并确认为有效...

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_date的天数值是否大于NOW() ...

EXTRACT( DAY FROM created_date ) >= EXTRACT( DAY FROM NOW() )

因此,如果NOW()的结尾的值不大于created_date的日值,那么它们可以被认为是等价的(因此以下代码),例如NOW()的日期= 2017-02-28与created_date的2017-01-31,或NOW()的约会= 2017-04 -30对比created_date&#39; 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() )

如果您有任何问题或意见,请相应发表评论。

答案 2 :(得分:1)

首先,让我们更好地了解您的要求。您需要所有记录,时间戳列(created_date)和&amp;当前时间(now())具有以下关系:

  • 的时间完全相同
    • 具有完全相同的一天
    • created_date有一天,大于now()天 仅当now()位于当月的最后一天时,
SELECT *
FROM   mytable
WHERE  EXTRACT(hour FROM created_date) = EXTRACT(hour FROM now())
AND    (EXTRACT(day FROM created_date) = EXTRACT(day  FROM now())
OR      CASE
          WHEN EXTRACT(month FROM CURRENT_DATE + 1) <> EXTRACT(month FROM CURRENT_DATE)
          THEN EXTRACT(day FROM created_date) > EXTRACT(day FROM now())
          ELSE FALSE
        END)

http://rextester.com/TXGCSI34243

注意:如果要为解决方案绑定timestamp(实际上不使用now()&amp; current_date函数),请使用{{1测试绑定时间戳是否是其月份的最后一天。