创建日期序列并将每个日期插入查询

时间:2014-09-19 10:53:24

标签: postgresql date

我需要在当月的第一天到当月的最后一天找到某些数据。

 select count(*) from q_aggr_data as a 
       where a.filial_='fil1'
       and a.operator_ like 'unit%' 
       and date_trunc('day',a.s_end_)='"+ date_to_search+ "' 
       group by a.s_name_,date_trunc('day',a.s_end_)

date_to_searh这里是01.09.2014,02.09.2014,03.09.2014,...,30.09.2014

我试图遍历i = 0 ... 30并进行30次查询,但这需要太长时间且非常幼稚。此外,对于没有条目的日子,它应该返回0.我已经看到了如何生成日期序列,但无法了解如何将这些日子逐个注入查询

3 个答案:

答案 0 :(得分:1)

通过不仅创建一系列,而且创建一组1天范围,可以使用> = with<任何时间戳数据连接到该范围。

特别注意,这种方法避免了数据上的函数(例如截断到日期),因此它允许使用索引来帮助查询性能。

如果某些数据如下所示:

CREATE TABLE my_data
    ("data_dt" timestamp)
;

INSERT INTO my_data
    ("data_dt")
VALUES
    ('2014-09-01 08:24:00'),
    ('2014-09-01 22:48:00'),
    ('2014-09-02 13:12:00'),
    ('2014-09-03 03:36:00'),
    ('2014-09-03 18:00:00'),

然后可以使用outer join加入,因此仍会向生成的范围集(dt_start& dt_end对)报告无法匹配的范围

SELECT
        r.dt_start
      , count(d.data_dt)
FROM (
      SELECT
            dt_start
          , dt_start + INTERVAL '1 Day' dt_end 
      FROM
           generate_series('2014-09-01 00:00'::timestamp,
                           '2014-09-30 00:00', '1 Day') AS dt_start
     ) AS r
LEFT OUTER JOIN my_data d ON d.data_dt >= r.dt_start
                         AND d.data_dt <  r.dt_end
GROUP BY
        r.dt_start
ORDER BY
        r.dt_start
;

产生了这样的结果:

|                         DT_START | COUNT |
|----------------------------------|-------|
| September, 01 2014 00:00:00+0000 |     2 |
| September, 02 2014 00:00:00+0000 |     1 |
| September, 03 2014 00:00:00+0000 |     2 |
| September, 04 2014 00:00:00+0000 |     2 |
 ...
| September, 29 2014 00:00:00+0000 |     0 |
| September, 30 2014 00:00:00+0000 |     0 |

See this SQLFiddle demo

答案 1 :(得分:0)

解决此问题的一种方法是按截断日期进行分组。

select count(*)
from q_aggr_data as a 
where a.filial_='fil1'
and a.operator_ like 'unit%' 
group by date_trunc('day',a.s_end_), a.s_name_;

另一种方法是使用window function来获取截断日期的计数。

答案 2 :(得分:0)

请检查此查询是否符合您的要求:

select sum(matched) -- include s_name_, s_end_ if you want to verify the results
from
(select a.filial_
, a.operator_
, a.s_name_
, generate_series s_end_
, (case when a.filial_ = 'fil1' then 1 else 0 end) as matched
from q_aggr_data as a 
right join generate_series('2014-09-01', '2014-09-30', interval '1 day')
     on a.s_end_ = generate_series
     and a.filial_ = 'fil1'
     and a.operator_ like 'unit%') aa
group by s_name_, s_end_
order by s_end_, s_name_

http://sqlfiddle.com/#!15/e8edf/3