2016-09-14 2 views
10

Verwendung habe ich Methode wie folgt:Wie PG :: NumericValueOutOfRange zu vermeiden, wenn Summenfunktion

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 

Wenn die Säule ein decimal ist, ist es noch ein Wert ohne Problem zurückgibt. Aber wenn die Spalte integer ist, endet die Methode mit einem PG::NumericValueOutOfRange Fehler.

Sollte ich den Spaltentyp integer zu decimal ändern, oder gibt es eine Möglichkeit, das Ergebnis sum ohne Änderung des Spaltentyps zu erhalten?

Antwort

2

Sie können Ihren Wert für alway werfen einen Dezimalwert sein, so dass keine Notwendigkeit, den Spaltentyp zu ändern:

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

P. S. Ich würde mit der Änderung des Spaltentyps gehen - es ist konsistent dann.

4

Sie können immer float aus Ihrer Ganzzahl machen.

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 
+0

'column' ist Spaltenname eines Modells in Dezimalzahlen. Das ist nur 'String' oder' Symbol'. – ironsand

2

Ich würde Ihnen vorschlagen, um den Datentyp zu decimal zu ändern. Denn wenn SUM PG::NumericValueOutOfRange bekommt, bedeutet das, dass Ihr Datentyp nicht ausreicht. Es wird dazu führen, dieses Szenario statt einer Problemumgehung ordnungsgemäß zu behandeln.

+0

Alle Werte in der Spalte sind klein genug für die 'Integer', ich bekomme nur den Fehler bei der Berechnung der Funktion von SQL. Wenn möglich, möchte ich den Spaltentyp nicht ändern. – ironsand

2

Postgres documentation sagt über SUM() Rückgabetyp:

Bigint für smallint oder Argumente int, numerisch für Bigint Argumente, sonst das gleiche wie das Argument Datentyp

Das bedeutet, dass Sie müssen irgendwie den Datentyp ändern, den Sie an SUM übergeben. Dies kann einer der folgenden Werte sein:

  • Tabelle ändern, um den Spaltentyp zu ändern.
  • Cast Spalte zu anderen Datentyp in Ihrer Methode.
  • Erstellen Sie eine Ansicht, die alle Integer-Spalten auf numerisch umwandelt und diese in Ihrer Methode verwendet.
2

Sie versuchen, einen Dezimalwert in einen Integer-Parameter zu platzieren. Sofern Sie nicht die ABS() Wert verwenden, wird nicht möglich sein, es sei denn, Sie zu 100% sicher sind, dass der Wert% immer 0.

Nutzungsart Float oder Funktion ABS() sein wird, wenn Sie eine INT

haben
0

Yo versuchen könnte Casting Spalte

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