Как избежать PG:: NumericValueOutOfRange при использовании функции суммы

У меня есть такой способ:

  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

Когда столбец равен decimal, он возвращает значение без проблем. Но когда столбец integer, метод заканчивается ошибкой PG::NumericValueOutOfRange.

Следует ли мне изменить тип столбца integer на decimal, или есть способ получить результат sum без изменения типа столбца?

Ответ 1

Вы можете указать свое значение так, чтобы оно было десятичным значением, поэтому не нужно изменять тип столбца:

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

P.S. Я бы пошел с изменением типа столбца - он последователен, затем.

Ответ 2

Вы всегда можете сделать 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

Ответ 3

Я бы предложил вам изменить тип данных на decimal. Потому что, когда SUM получает PG::NumericValueOutOfRange, это означает, что вашего типа данных недостаточно. Это приведет к изящному решению этого сценария, а не к обходному пути.

Ответ 4

Документация Postgres говорит об этом в виде возвращаемого типа SUM():

bigint для аргументов smallint или int, числовых аргументов bigint, в противном случае то же самое, что и тип данных аргумента

Это означает, что вам нужно каким-то образом изменить тип данных, который вы передадите SUM. Это может быть одно из следующего:

  • Изменить таблицу для изменения типа данных столбца.
  • Вставьте столбец в другой тип данных в свой метод.
  • Создайте представление, в котором все целые столбцы будут числиться и будут использоваться в вашем методе.

Ответ 5

Вы пытаетесь поместить десятичное значение в целочисленный параметр. Если вы не используете значение ABS(), которое будет невозможно, если вы на 100% не уверены, что значение% всегда будет 0.

Используйте тип Float или функцию ABS(), если у вас есть INT

Ответ 6

Yo может попробовать лить колонку в десятичный

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