Ruby ActiveRecord 组和“AS”处或附近的平均“语法错误”

Posted

技术标签:

【中文标题】Ruby ActiveRecord 组和“AS”处或附近的平均“语法错误”【英文标题】:Ruby ActiveRecord group and average "syntax error at or near "AS"" 【发布时间】:2017-03-16 07:05:28 【问题描述】:
params = device_id: "u100", device_point: "1", point_no: "1", max_date: "2016-12-01 12:00", min_date: "2016-12-01 11:40"

我正在使用 PG 数据库的 ruby​​/rails 环境中工作。

我正在尝试添加到我的设备控制器以使用 ActiveRecord 从一些虚拟传感器数据中获取 10 分钟的平均值。 我可以按分钟分组;

.group("date_trunc('minute', device_time)").average('point_data_val')

例如

device_data = DeviceDatum.select('device_time, point_data_val').filter(params.slice(:device_id, :device_point, :point_no, :iot_version, :iot_time, :device_time, :point_data_type, :point_data_val, :point_bat_val,:min_val, :max_val, :min_date, :max_date)).limit(1008).group("date_trunc('minute', device_time)").average('point_data_val')
   (240.3ms)  SELECT  AVG("device_data"."point_data_val") AS average_point_data_val, date_trunc('minute', device_time) AS date_trunc_minute_device_time FROM "device_data" WHERE "device_data"."device_id" = $1 AND "device_data"."device_point" = $2 AND "device_data"."point_no" = $3 AND (device_time >= '2016-12-01 11:40') AND (device_time <= '2016-12-01 12:00') GROUP BY date_trunc('minute', device_time) LIMIT 1008  [["device_id", "u100"], ["device_point", 1], ["point_no", 1]]
=> 2016-12-01 11:41:00 +0900=>#<BigDecimal:7f91599cfbc0,'-0.4816E1',18(27)>, 2016-12-01 11:51:00 +0900=>#<BigDecimal:7f91599cf8f0,'-0.4868E1',18(27)>

我找到了this method 来做这件事 但是当我尝试在组方法中使用 AS 时

DeviceDatum.select('device_time, point_data_val')
.filter(params.slice(:device_id, :device_point, :point_no, :iot_version, :iot_time, :device_time, 
:point_data_type, :point_data_val, :point_bat_val,:min_val, :max_val, :min_date, 
:max_date)).limit(1008)
.group("date_trunc('hour', device_time) AS hour_stump,
(extract(minute FROM device_time)::int / 10) 
AS min10_slot,count(*)").average('point_data_val')

我收到此错误。

ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR:  syntax error at or near "AS"
LINE 1: ... 12:00') GROUP BY date_trunc('hour', device_time) AS hour_st... : SELECT  AVG("device_data"."point_data_val") AS average_point_data_val, date_trunc('hour', device_time) AS hour_stump,(extract(minute FROM device_time)::int / 10) AS min10_slot,count(*) AS date_trunc_hour_device_time_as_hour_stump_extract_minute_from_d FROM "device_data" WHERE "device_data"."device_id" = $1 AND "device_data"."device_point" = $2 AND "device_data"."point_no" = $3 AND (device_time >= '2016-12-01 11:40') AND (device_time <= '2016-12-01 12:00') GROUP BY date_trunc('hour', device_time) AS hour_stump,(extract(minute FROM device_time)::int / 10) AS min10_slot,count(*) LIMIT 1008
from ...../bundle/ruby/2.1.0/gems/activerecord-4.2.6/lib/active_record/connection_adapters/postgresql_adapter.rb:637:in `prepare'

ActiveRecord 似乎也在使用它为平均值生成的 sql 中的 group 方法中的选项。

 SELECT
   AVG("device_data"."point_data_val") AS average_point_data_val,
   date_trunc('hour', device_time) AS hour_stump,
   (
      extract(minute 
   FROM
      device_time)::int / 10
   )
   AS min10_slot,
   count(*) AS date_trunc_hour_device_time_as_hour_stump_extract_minute_from_d 
FROM
   "device_data" 
WHERE
   "device_data"."device_id" = $1 
   AND "device_data"."device_point" = $2 
   AND "device_data"."point_no" = $3 
   AND 
   (
      device_time >= '2016-12-01 11:40'
   )
   AND 
   (
      device_time <= '2016-12-01 12:00'
   )
GROUP BY
   date_trunc('hour', device_time) AS hour_stump,
   (
      extract(minute 
   FROM
      device_time)::int / 10
   )
   AS min10_slot,
   count(*) LIMIT 1008

我在这里错过了什么?

【问题讨论】:

如果我没记错的话你只能在SELECT中使用AS 您在group by 子句中尝试做的事情是否可行?您所指的问题在 select 子句中使用了这个技巧。 【参考方案1】:

我认为你的group 子句应该是这样的:

group("hour_stump, min10_slot,
       date_trunc_hour_device_time_as_hour_stump_extract_minute_from_d")

如果您在select 子句中使用别名。正如@Fallenhero 和@Iceman 所说,group by 中的别名是不允许的。

如果在select 中自动替换别名,我认为唯一的方法是按原样使用函数

group("date_trunc('hour', device_time),
(extract(minute FROM device_time)::int / 10), count(*)")

.

【讨论】:

谢谢,我选择了:group("to_char(date_trunc('hour', device_time), 'YYYY-MM-DD HH:') || to_char((extract(minutes FROM device_time)::int / 10*10), 'fm00')"),这给了:[["2016-12-01 11:00", #&lt;BigDecimal:7f883988e348,'-0.3998E1',18(27)&gt;], ["2016-12-01 11:10", #&lt;BigDecimal:7f883988e500,'-0.4274E1',18(27)&gt;], ["2016-12-01 11:20", #&lt;BigDecimal:7f883988e438,'-0.453E1',18(27)&gt;], ["2016-12-01 11:30", #&lt;BigDecimal:7f883988e758,'-0.4605E1',18(27)&gt;], ["2016-12-01 11:40", #&lt;BigDecimal:7f883988e690,'-0.4816E1',18(27)&gt;], ["2016-12-01 11:50", #&lt;BigDecimal:7f883988e5c8,'-0.4868E1',18(27)&gt;]] 已更新为group("to_timestamp(to_char(date_trunc('hour', device_time), 'YYYY-MM-DD HH:') || (to_char((extract(minutes FROM device_time)::int / 10*10), 'fm00')), 'YYYY-MM-DD HH:MI')::timestamp without time zone").calculate(params[:func], 'point_data_val') 这会将输出格式化为漂亮的时间戳,并且'::time stamp without time zone' 将时间缩短了九个小时

以上是关于Ruby ActiveRecord 组和“AS”处或附近的平均“语法错误”的主要内容,如果未能解决你的问题,请参考以下文章

导致 ActiveRecord 记录器 IOError 的 Ruby 守护进程

“as”的 Activerecord 方法 - 派生别名

ruby 没有Rails的Activerecord

ruby 没有Rails的Activerecord

ruby 否定ActiveRecord范围

ruby 使用csv的ActiveRecord错误