2017-04-03 67 views
0

我想抓取所有在ℕ個月前創建的記錄,完全相同的小時。 (的記錄年齡應該只有ℕ個月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查詢可以在任何這些timstamps來執行,但應返回相同的行爲expected_records狀態的量。 你也可以使用'some date'::timestamp而不是現在()來僞造時間。

+0

要確認,您正在計算日曆月,而不是30天等。 – toonice

+0

正確。 @toonice我不算30天,我要N個月的記錄。 – Rahman

+0

'2010-11-15 13:46:23'(不同的年份和分鐘/秒)被列出嗎? – toonice

回答

1

首先,讓我們試着更好地理解您的要求。你需要的所有記錄,爲此,時間戳列(created_date)&當前時間(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() & current_date功能),然後使用WHEN EXTRACT(month FROM ? + INTERVAL '1 day') > EXTRACT(month FROM ?)來測試是否綁定時間戳是其月份的最後一天,或者不是。

+0

請注意,上面的代碼是無效的,而來自rextester的代碼是。我把你的注意力放在兩條語句的第6行。 – toonice

+0

@toonice無效的意思是什麼?他們是一樣的。 – pozs

+0

在上面的第6行中,您正在'current_date'上測試以查看它是否在月末,而您應該測試'NOW()'(因爲您在測試代碼中)。 – toonice

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) 
+0

它實際上並不是真的,因爲最後我想每小時運行一次這個查詢,我期望得到不同的結果,而不是每個月。 加上,即使它可以這樣調整,似乎也有一些遺漏的日子。例如,如果你執行這個查詢:'SELECT generate_series('2016-01-31 13:00:00':: timestamp,'2018-01-31':: DATE,'1 month':: interval) - '1 day':: interval lastday;'你會在'2017-02-27'後看到發生了什麼' – Rahman

+0

請在我的答案中查看該函數。我根據你的陳述創建它,你有確切的日期和時間來比較。你不能使用任何日期作爲'generate_series'的參數讓邏輯工作(這就是爲什麼我決定把邏輯包裝到函數中) - 嘗試帶有令你困惑的日期的函數,請告訴它是否工作 –

+0

感謝您的出色答案但我已經更新了我的問題,提供了一些樣本來測試和驗證。 – Rahman

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年2月28日與created_date的2017年1月31日,或NOW()的日期= 2017年4月30日與created_date的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()) 

如果您有任何問題或意見,請相應發表評論。

+0

感謝您的出色答案,但我更新了我的問題,提供了一些樣品來測試和驗證。 – Rahman

+0

我已經使用您提供的示例表格和數據測試了我的代碼,以及一些額外的行,根據我當前的日期和時間應該或不應該產生結果。它似乎按照規定工作。如果沒有,請提供描述性錯誤報告。 – toonice

+0

'SELECT * FROM mytable WHERE EXTRACT(HOUR FROM'2017-02-28 13:22:00':: timestamp)= EXTRACT(HOUR FROM created_date) AND EXTRACT(DAY FROM'2017-02-28 13: 22:00':: timestamp)= EXTRACT(DAY FROM created_date);'返回5行時返回2. – Rahman