【问题标题】:Aggregate numbers, some in ranges汇总数字,一些在范围内
【发布时间】:2020-06-26 22:50:47
【问题描述】:

我有一个表tab1,在我的数字列c1 中有以下值:

1
2
3
4
5
6
7
8
9
10
13
18

我想回来

1-5
6-10
13
18

下面的查询在 MySQL 而不是 PostgreSQL 中成功执行:

select distinct
case
when c1 between 1 and 5 then '1-5'
when c1 between 6 and 9 then '6-10'
else c1
end as 'c1'
from tab1;

【问题讨论】:

标签: sql postgresql aggregate gaps-and-islands natural-sort


【解决方案1】:

修复语法错误并正确转换后,相同的查询在 Postgres 中有效:

SELECT DISTINCT
       CASE WHEN c1 BETWEEN 1 AND 5 THEN '1-5'
            WHEN c1 BETWEEN 6 AND 9 THEN '6-10'
            ELSE c1::text END AS c1 
FROM   tab1;

结果必须是字符串类型 - text 是 Postgres 中的首选类型。但是按字符串表示排序对您的数字没有好处。所以我建议这种替代方法允许正确排序:

SELECT CASE WHEN c1 BETWEEN 1 AND 5 THEN '1-5'
            WHEN c1 BETWEEN 6 AND 9 THEN '6-10'
            ELSE c1::text END AS new_c1   -- avoid duplicate of source name
FROM   tab1 t
GROUP  BY new_c1
ORDER  BY min(t.c1);

db小提琴here

【讨论】:

    【解决方案2】:

    如果我理解正确,您将使用两个级别的聚合。第一个获取范围:

    select min(c1), max(c1)
    from (select t.*, row_number() over (order by c1) as seqnum
          from t
         ) t
    group by c1 - seqnum;
    

    第二个然后重新聚合:

    select string_agg(range, ',' order by min_c1)
    from (select (case when min(c1) <> max(c1) then min(c1) || '-' || max(c1) else min(c1)::text end) as range, min(c1) as min_c1
          from (select t.*, row_number() over (order by c1) as seqnum
                from t
               ) t
          group by c1 - seqnum
         ) x
    

    Here 是一个 dbfiddle,说明此逻辑有效。

    【讨论】:

    • 两个查询都有错误,并且(修复后)都不会产生 OP 要求的内容。
    猜你喜欢
    • 2014-03-05
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 2017-07-26
    • 2011-01-09
    • 1970-01-01
    相关资源
    最近更新 更多