Postgres查询范围内的10个步骤

时间:2014-06-23 20:33:19

标签: sql ruby-on-rails postgresql aggregate-functions generate-series

我们有一个带Postgres的RAILS应用程序作为数据库,并有一个用例来绘制一系列值的图形。不幸的是,范围是小数,所以我无法使用Postgres的generate_series函数。需要帮助找出查询此方法的最佳方法,而不是将其拆分为10个不同的查询。这是示例数据

  • 我们有一张得分的表格学生
  • 鉴于一个查询,我会得到一组得分 - 学生元组,从中得到范围(分(分数),最大(分数))。例如范围(10.25,16.80)
  • 我们需要将上述范围分为10个步骤,间隔为0.655,即(max-min)10 - 10.25,10.91,11.56,12.22,12.87
  • 上述每个步骤都会显示该分数与之前值之间的学生数
  • 结果将是[(10.25,11232),(10.91,2434),....]
  • 的数组

在Postgres中以单个查询或少于10个以上的查询执行此操作的任何方式/想法?

1 个答案:

答案 0 :(得分:1)

您的结果设置(对我来说更有意义):

WITH base AS (
   SELECT student, score
   FROM   tbl
   WHERE  <some_condition>
   )
, border AS (
   SELECT min(score) AS min_score, max(score) AS max_score
   FROM   base
   )
SELECT lower_bound, ct
FROM  (
   SELECT step
        , min_score + ((max_score - min_score) * (step-1)) / 10 AS lower_bound
   FROM   border, generate_series(1,10) step
   ) x
LEFT   JOIN (
   SELECT width_bucket(b.score, x.min_score, x.max_score, 10) AS step
        , count(*)::int AS ct
   FROM   border x, base b
   GROUP  BY step
   ) y USING (step)
ORDER  BY step;

有两个CTEsgenerate_series()(仍然有用)和经常被忽视的函数width_bucket()

要生成复合类型数组,如问题中所述,首先创建一个匹配类型(一次):

CREATE TYPE my_type AS (bound numeric, ct int);

假设缺少信息的numeric值 然后将以上查询提供给array constructor

SELECT ARRAY (
   <query from above>
   SELECT (lower_bound, ct::int)::my_type   -- only difference
   <query from above>
   );