lib/active_median/model.rb in active_median-0.2.3 vs lib/active_median/model.rb in active_median-0.2.4
- old
+ new
@@ -1,8 +1,18 @@
module ActiveMedian
module Model
def median(column)
+ percentile(column, 0.5)
+ end
+
+ def percentile(column, percentile)
+ percentile = percentile.to_f
+ raise ArgumentError, "percentile is not between 0 and 1" if percentile < 0 || percentile > 1
+
+ # prevent SQL injection
+ percentile = connection.quote(percentile)
+
group_values = all.group_values
relation =
case connection.adapter_name
when /mysql/i
@@ -13,24 +23,34 @@
if mariadb
if group_values.any?
over = "PARTITION BY #{group_values.join(", ")}"
end
- select(*group_values, "PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY #{column}) OVER (#{over})").unscope(:group)
+ select(*group_values, "PERCENTILE_CONT(#{percentile}) WITHIN GROUP (ORDER BY #{column}) OVER (#{over})").unscope(:group)
else
# if mysql gets native function, check (and memoize) version first
- select(*group_values, "PERCENTILE_CONT(#{column}, 0.50)")
+ select(*group_values, "PERCENTILE_CONT(#{column}, #{percentile})")
end
when /sqlserver/i
if group_values.any?
over = "PARTITION BY #{group_values.join(", ")}"
end
- select(*group_values, "PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY #{column}) OVER (#{over})").unscope(:group)
+ select(*group_values, "PERCENTILE_CONT(#{percentile}) WITHIN GROUP (ORDER BY #{column}) OVER (#{over})").unscope(:group)
when /sqlite/i
- select(*group_values, "MEDIAN(#{column})")
+ case percentile.to_f
+ when 0
+ select(*group_values, "MIN(#{column})")
+ when 0.5
+ select(*group_values, "MEDIAN(#{column})")
+ when 1
+ select(*group_values, "MAX(#{column})")
+ else
+ # LOWER_QUARTILE and UPPER_QUARTILE use different calculation than 0.25 and 0.75
+ raise "SQLite only supports 0, 0.5, and 1 percentiles"
+ end
when /postg/i, /redshift/i # postgis too
- select(*group_values, "PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY #{column})")
+ select(*group_values, "PERCENTILE_CONT(#{percentile}) WITHIN GROUP (ORDER BY #{column})")
else
raise "Connection adapter not supported: #{connection.adapter_name}"
end
result = connection.select_all(relation.to_sql)