2016-09-14 16 views
10

tôi có phương pháp như thế này:Làm thế nào để tránh PG :: NumericValueOutOfRange khi sử dụng chức năng tổng

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 

Khi cột là một decimal, nó sẽ trả về một giá trị mà không có vấn đề. Nhưng khi cột là integer, phương pháp kết thúc bằng lỗi PG::NumericValueOutOfRange.

Tôi có nên thay đổi loại cột integer thành decimal hoặc có cách nào để nhận kết quả của sum mà không thay đổi loại cột không?

Trả lời

2

Bạn có thể đúc giá trị của bạn để tính toán luôn là một giá trị thập phân, do đó không cần phải thay đổi loại cột:

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

T.B. Tôi sẽ thay đổi kiểu cột - nó là nhất quán rồi.

4

Bạn luôn có thể thực hiện float từ số nguyên của mình.

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' là tên cột của mô hình. Đó chỉ là 'String' hoặc' Symbol'. – ironsand

2

Tôi khuyên bạn nên thay đổi kiểu dữ liệu thành decimal. Bởi vì, khi SUM được PG::NumericValueOutOfRange, điều đó có nghĩa là kiểu dữ liệu của bạn không đủ. Nó sẽ dẫn đến xử lý một cách duyên dáng kịch bản này, thay vì một cách giải quyết khác.

+0

Tất cả các giá trị trong cột đủ nhỏ cho 'số nguyên', tôi chỉ gặp lỗi khi sử dụng hàm tính toán của SQL. Nếu có thể tôi muốn tránh thay đổi loại cột. – ironsand

2

Postgres documentation nói này về SUM() kiểu trả về:

bigint cho smallint hoặc int đối số, số cho các đối số bigint, nếu không giống như các kiểu dữ liệu tham số

Điều này có nghĩa rằng bạn bằng cách nào đó sẽ cần phải thay đổi kiểu dữ liệu mà bạn chuyển sang SUM. Có thể là một trong những điều sau:

  • Thay đổi bảng để thay đổi kiểu dữ liệu cột.
  • Cột truyền đến kiểu dữ liệu khác trong phương thức của bạn.
  • Tạo chế độ xem biểu diễn tất cả các cột số nguyên thành số và sử dụng số đó trong phương thức của bạn.
2

Bạn đang cố gắng đặt một giá trị thập phân vào một tham số nguyên. Trừ khi bạn sử dụng giá trị ABS() sẽ không thể thực hiện được, trừ khi bạn chắc chắn rằng giá trị% sẽ luôn là 0.

Sử dụng loại Float hoặc chức năng ABS() nếu bạn có INT

0

Bạn có thể thử truyền cột sang số thập phân

sql = "SUM(CAST(#{column}) AS DECIMAL * market_cap)/SUM(market_cap) as weighted_average" 
Các vấn đề liên quan