请考虑以下查询:
SELECT DATE_TRUNC('hour',date_range) FROM GENERATE_SERIES(:start_date,:end_date,:interval) as date_range
是否可以使用GENERATE_SERIES(…)作为表(数据源)?理想情况下,它看起来像这样:
t = series(start,end,as: 'date_range') dt = Arel::Nodes::NamedFunction.new('DATE_TRUNC',['hour',t[:date_range]]) t.project(dt)
Upd1.为什么我需要GENERATE_SERIES?我有一些数据需要处理这个数据可用的时间戳,并将其输出为2D图.作为一个简单的例子,考虑一个clickstream =(id,created_at).我想绘制在特定日期之前针对给定日期时间网格(即11月17日,11月18日,11月19日,…,11月30日)进行的点击次数.事情是我希望这一切都发生在Postgresql中.
UPD2.没有变量的示例查询可能如下所示:
SELECT DATE_TRUNC('hour',date_range) FROM GENERATE_SERIES('2015-01-01 00:15:38'::TIMESTAMP,'2015-01-10 23:59:59'::TIMESTAMP,'1 HOUR') as date_range;
解决方法
一种方法是简单地手动构建AST的所有必要部分
def timestamp(ts) Arel::Nodes::NamedFunction.new( 'CAST',[ Arel::Nodes::As.new( Arel::Nodes.build_quoted(ts),Arel::Nodes::sqlLiteral.new('timestamp') ) ] ) end def series(from,to,by,options = {}) Arel::Nodes::NamedFunction.new( 'GENERATE_SERIES',[ timestamp(from),timestamp(to),Arel::Nodes::sqlLiteral.new(by) ] ).as(options.fetch(:as,'series')) end def date_trunc(by,attribute) Arel::Nodes::NamedFunction.new( 'DATE_TRUNC',[Arel.sql("'#{by}'"),attribute] ) end date_range = Arel::Table.new('date_range') result = date_range. from(series(5.days.ago,4.days.ago,"'1 hour'",as: 'date_range')). project(date_trunc('hour',date_range[:date_range]))
测试:
User.find_by_sql(result.to_sql).to_a.map &:attributes SELECT DATE_TRUNC('hour',"date_range"."date_range") FROM GENERATE_SERIES( CAST('2015-02-03 21:29:22.729188' AS timestamp),CAST('2015-02-04 21:29:22.729633' AS timestamp),'1 hour' ) AS date_range [{"date_trunc"=>2015-02-03 21:00:00 UTC,"id"=>nil},{"date_trunc"=>2015-02-03 22:00:00 UTC,{"date_trunc"=>2015-02-03 23:00:00 UTC,{"date_trunc"=>2015-02-04 00:00:00 UTC,# ... {"date_trunc"=>2015-02-04 21:00:00 UTC,"id"=>nil}]