简体   繁体   中英

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. But when the column is integer , the method ends up with a PG::NumericValueOutOfRange error.

Should I change column type integer to decimal , or is there a way to get the result of sum without changing column type?

You can always make float from your integer.

  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 . Because, when SUM gets PG::NumericValueOutOfRange , it means that your datatype is not sufficient. 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.

Postgres documentation says this about SUM() return type:

bigint for smallint or int arguments, numeric for bigint arguments, otherwise the same as the argument data type

This means that you will somehow need to change datatype that you pass to 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.

Use type Float or function ABS() if you HAVE to have an INT

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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