简体   繁体   English

使用sum函数时如何避免PG :: NumericValueOutOfRange

[英]How to avoid PG::NumericValueOutOfRange when using sum function

I have method like this: 我有这样的方法:

  def self.weighted_average(column)
    sql = "SUM(#{column} * market_cap) / SUM(market_cap) as weighted_average"
    Company.select(sql).to_a.first.weighted_average
  end

When the column is a decimal , it returns a value without problem. 当列是decimal ,它返回一个没有问题的值。 But when the column is integer , the method ends up with a PG::NumericValueOutOfRange error. 但是当列是integer ,该方法最终会出现PG::NumericValueOutOfRange错误。

Should I change column type integer to decimal , or is there a way to get the result of sum without changing column type? 我应该将列类型integer更改为decimal ,还是有办法在不更改列类型的情况下获得sum的结果?

You can always make float from your integer. 你总是可以从整数中float

  def self.weighted_average(column)
    column = column.to_f
    sql = "SUM(#{column} * market_cap) / SUM(market_cap) as weighted_average"
    Company.select(sql).to_a.first.weighted_average
  end

I would suggest you to change the datatype to decimal . 我建议你将数据类型更改为decimal Because, when SUM gets PG::NumericValueOutOfRange , it means that your datatype is not sufficient. 因为,当SUM获取PG::NumericValueOutOfRange ,这意味着您的数据类型不足。 It will lead to gracefully handle this scenario, instead of a workaround. 它将导致优雅地处理此方案,而不是解决方法。

You can cast your value to alway be a decimal value, thus no need to change the column type: 您可以将值转换为小数值,因此无需更改列类型:

sql = "SUM(#{column} * CAST(market_cap as decimal(53,8))) / SUM(CAST(market_cap as decimal(53,8))) as weighted_average"

PS I would go with changing the column type - it is consistent then. PS我会改变列类型 - 它是一致的

Postgres documentation says this about SUM() return type: Postgres文档说这个关于SUM()返回类型:

bigint for smallint or int arguments, numeric for bigint arguments, otherwise the same as the argument data type smallint或int参数的bigint,bigint参数的numeric,否则与参数数据类型相同

This means that you will somehow need to change datatype that you pass to SUM. 这意味着您将以某种方式需要更改传递给SUM的数据类型。 It can be one of the following: 它可以是以下之一:

  • Alter table to change column datatype. 更改表以更改列数据类型。
  • Cast column to other datatype in your method. 将列转换为方法中的其他数据类型。
  • Create a view that casts all integer columns to numeric and use that in your method. 创建一个视图,将所有整数列转换为数字,并在方法中使用它。

You are trying to place a decimal value into a integer parameter. 您正在尝试将十进制值放入整数参数。 Unless you use the ABS() value that will not be possible, unless you are 100% sure that the % value will always be 0. 除非您使用无法实现的ABS()值,否则除非您100%确定%值始终为0。

Use type Float or function ABS() if you HAVE to have an INT 如果您必须拥有INT,请使用类型Float或函数ABS()

哟可以尝试将列转换为十进制

sql = "SUM(CAST(#{column}) AS DECIMAL * market_cap) / SUM(market_cap) as weighted_average"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM