Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 获取具有每月创建日期周期的记录_Sql_Postgresql - Fatal编程技术网

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

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:

我想抓取所有已创建的记录ℕ 一个月前,就在同一个小时。(记录的年龄应为ℕ 月、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: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()
&
current_date
函数),则使用
提取时(月自?+间隔“1天”)>提取(月自?
测试绑定的时间戳是否为其月份的最后一天。

首先,让我们试着更好地理解您的需求。您需要所有记录,其时间戳列(
created\u date
)和当前时间(
now()
)具有以下关系:

  • 具有完全相同的小时数
    • 正好在同一天
    • created\u date
      有一个日期,它大于
      now()
      的日期
      仅当
      now()
      在当月的最后一天时

选择*
从mytable
其中EXTRACT(从创建日期算起的小时)=EXTRACT(从现在算起的小时())
和(提取(从创建日期算起的日期)=提取(从现在算起的日期())
或案例
提取时(从当前日期算起的月份+1)提取时(从当前日期算起的月份)
然后提取(从创建日期算起的日期)>提取(从现在算起的日期())
否则错误
(完)

注意:如果要为解决方案绑定
时间戳
s(实际上不使用
now()
&
当前日期
函数),则在提取时使用
(从+