在 Postgres SQL 中如何将值转换为范围并获取具有最大记录的范围

In Postgres SQL how to convert values as range and get the range with maximum records

有 table 名学生的姓名和年龄如下如何将年龄值转换为

的范围

并获取学生人数最多的年龄范围

正在创建 table:

CREATE TABLE students (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  age FLOAT NOT NULL
);

正在插入值:

INSERT INTO students
VALUES
(1, 'Ryan', 12),
(2, 'Joanna', 12.5),
(3, 'James', 11),
(4, 'Karen', 10),
(5, 'Holmes', 11.2),
(6, 'Garry', 12.1),
(7, 'Justin', 14.5),
(8, 'Emma', 15),
(9, 'Andy', 10),
(10, 'Claren', 9.5),
(11, 'Dennis', 9),
(12, 'Henna', 16),
(13, 'Iwanka', 15.4),
(14, 'June', 8.1),
(15, 'Kamila', 7.5),
(16, 'Lance', 17);

预期输出应在最大记录数范围内:

Range | Count 
10-12 | 5

您可以尝试使用带有 CASE WHEN 表达式的聚合函数作为您的逻辑,然后使用 ORDER BY COUNT DESC 获取最大记录数

SELECT (CASE WHEN age BETWEEN 7 AND 9 THEN '7-9'
           WHEN age BETWEEN 10 AND 12 THEN '10-12'
           WHEN age BETWEEN 13 AND 15 THEN '13-15'
           WHEN age BETWEEN 15 AND 17 THEN '15-17'
           WHEN age BETWEEN 17 AND 19 THEN '17-19' END) as range,
      COUNT(*) cnt
FROM students
GROUP BY  CASE WHEN age BETWEEN 7 AND 9 THEN '7-9'
           WHEN age BETWEEN 10 AND 12 THEN '10-12'
           WHEN age BETWEEN 13 AND 15 THEN '13-15'
           WHEN age BETWEEN 15 AND 17 THEN '15-17'
           WHEN age BETWEEN 17 AND 19 THEN '17-19' END
ORDER BY COUNT(*) DESC 
LIMIT 1

编辑

如果您的范围编号有逻辑并且您想要一个通用的范围解决方案

您可以尝试使用 generate_series 使用您的范围逻辑生成范围编号,然后进行外部连接。

对于您的示例数据,我将使用 generate_series(7,17,2) 创建一个范围编号,您希望计算开始和结束编号

SELECT CONCAT(t1.startnum,'-',t1.endnum) as range,
      COUNT(*) cnt
FROM students s
INNER JOIN (
    SELECT v startnum,v+2 endnum
    FROM generate_series(7,17,2) v 
  ) t1 ON s.age BETWEEN t1.startnum AND t1.endnum
GROUP BY CONCAT(t1.startnum,'-',t1.endnum)
ORDER BY COUNT(*) DESC 
LIMIT 1

sqlfiddle

--构造numrange table.

CREATE TABLE age_range (
    id serial,
    agerange numrange
);

INSERT INTO age_range (agerange)
    VALUES ('[7,9]'), ('[10,12]'), ('[13,15]'), ('[15,17]'), ('[17,19]');

--cte 具有 window 功能。

  WITH a AS (
    SELECT
        age,
        name,
        agerange
    FROM
        students s,
        age_range b
    WHERE
        age <@ agerange IS TRUE
)
SELECT
    *,
    count(agerange) OVER (PARTITION BY agerange)
FROM
    a
ORDER BY
    agerange,
    name;