Postgresql:将逗号分隔的整数值和间隔转换为有序数字
Postgresql : Converting comma separated integer values and intervals to sequenced numbers
我有一个 table 包含以下内容:
Value 是一种 varchar
类型,用于存储 comma
和 dashes
等字符串字符,因此一切皆有可能。但通常它只包含 numbers
、comma
和 dash
来指定间隔。
id | value |
------------------
1 | 1,2,5,8-10 |
2 | 1,2,3 |
3 | 1-3 |
4 | 1-3, 4-5 |
5 | 1-2,2-3 |
我想执行 select
查询,以 "normalized" 代码可读格式 (逗号分隔) 在数据库级别检索值(不在代码级别),这就是为什么我需要 select 一个 table 是这样的。
id | value | normalized
-------------------------------
1 | 1,2,5,8-10 |1,2,5,8,9,10
2 | 1,2,3 |1,2,3
3 | 1-3 |1,2,3
4 | 1-3, 4-5 |1,2,3,4,5
5 | 1-2,2-3 |1,2,3
id为#5的记录的特殊情况,即使它指定了两次2,它仍然应该只检索一次2。 postgres
中是否已经有一个函数可以做到这一点?如果不是,我该如何解析字符串并在 Postgres sql
?
中对数字进行排序
对于您首选的 PL 中的过程或简单的 C 扩展,这似乎是一个很好的案例。 pl/perl、pl/pythonu 或 pl/v8 是我的选择。
也就是说,在 SQL 中这很容易。拆分以找到子范围,可以是单个数字或范围。然后对于每个范围generate_series超过它。
例如:
SELECT n
FROM
regexp_split_to_table('1,2,5,8-10', ',') subrange,
regexp_split_to_array(subrange, '-') subrange_parts,
generate_series(subrange_parts[1]::integer,
coalesce(subrange_parts[2], subrange_parts[1])::integer
) n;
您可以将其封装为 SQL
函数,或用作 table.
查询的一部分
应用于table,你会得到类似的东西:
CREATE TABLE example
("id" int, "value" varchar)
;
INSERT INTO example
("id", "value")
VALUES
(1, '1,2,5,8-10'),
(2, '1,2,3'),
(3, '1-3'),
(4, '1-3, 4-5'),
(5, '1-2,2-3')
;
当应用于 table 时,类似于:
SELECT
example.id,
array_agg(DISTINCT n) AS expanded_set
FROM
example,
regexp_split_to_table(example.value, ',') subrange,
regexp_split_to_array(subrange, '-') subrange_parts,
generate_series(subrange_parts[1]::integer,
coalesce(subrange_parts[2], subrange_parts[1])::integer
) n
GROUP BY
example.id;
结果(添加了原始列):
id | original_format | expanded_set
----+-----------------+----------------
1 | 1,2,5,8-10 | {1,2,5,8,9,10}
2 | 1,2,3 | {1,2,3}
3 | 1-3 | {1,2,3}
4 | 1-3, 4-5 | {1,2,3,4,5}
5 | 1-2,2-3 | {1,2,3}
(5 rows)
这不会特别快,但可能没问题。如果没有,用 C 写一些更快的东西作为扩展,或者 plperl 或其他东西。
要了解发生了什么,请阅读 PostgreSQL 手册部分:
GROUP BY
和聚合
- 聚合函数,特别是
array_agg
DISTINCT
作为聚合限定符
- PostgreSQL 数组,我在这里用作中间状态和结果
generate_series
函数
regexp_split_to_table
和 regexp_split_to_array
函数
LATERAL
查询,此处隐式使用这些查询,因为一个函数使用连接列表中另一个函数的结果。
以上示例仅适用于 PostgreSQL 9.2 及更新版本。如果您使用的是旧版本,则必须使用嵌套子查询层来解决缺少 LATERAL
的问题。
我有一个 table 包含以下内容:
Value 是一种 varchar
类型,用于存储 comma
和 dashes
等字符串字符,因此一切皆有可能。但通常它只包含 numbers
、comma
和 dash
来指定间隔。
id | value |
------------------
1 | 1,2,5,8-10 |
2 | 1,2,3 |
3 | 1-3 |
4 | 1-3, 4-5 |
5 | 1-2,2-3 |
我想执行 select
查询,以 "normalized" 代码可读格式 (逗号分隔) 在数据库级别检索值(不在代码级别),这就是为什么我需要 select 一个 table 是这样的。
id | value | normalized
-------------------------------
1 | 1,2,5,8-10 |1,2,5,8,9,10
2 | 1,2,3 |1,2,3
3 | 1-3 |1,2,3
4 | 1-3, 4-5 |1,2,3,4,5
5 | 1-2,2-3 |1,2,3
id为#5的记录的特殊情况,即使它指定了两次2,它仍然应该只检索一次2。 postgres
中是否已经有一个函数可以做到这一点?如果不是,我该如何解析字符串并在 Postgres sql
?
对于您首选的 PL 中的过程或简单的 C 扩展,这似乎是一个很好的案例。 pl/perl、pl/pythonu 或 pl/v8 是我的选择。
也就是说,在 SQL 中这很容易。拆分以找到子范围,可以是单个数字或范围。然后对于每个范围generate_series超过它。
例如:
SELECT n
FROM
regexp_split_to_table('1,2,5,8-10', ',') subrange,
regexp_split_to_array(subrange, '-') subrange_parts,
generate_series(subrange_parts[1]::integer,
coalesce(subrange_parts[2], subrange_parts[1])::integer
) n;
您可以将其封装为 SQL
函数,或用作 table.
应用于table,你会得到类似的东西:
CREATE TABLE example
("id" int, "value" varchar)
;
INSERT INTO example
("id", "value")
VALUES
(1, '1,2,5,8-10'),
(2, '1,2,3'),
(3, '1-3'),
(4, '1-3, 4-5'),
(5, '1-2,2-3')
;
当应用于 table 时,类似于:
SELECT
example.id,
array_agg(DISTINCT n) AS expanded_set
FROM
example,
regexp_split_to_table(example.value, ',') subrange,
regexp_split_to_array(subrange, '-') subrange_parts,
generate_series(subrange_parts[1]::integer,
coalesce(subrange_parts[2], subrange_parts[1])::integer
) n
GROUP BY
example.id;
结果(添加了原始列):
id | original_format | expanded_set
----+-----------------+----------------
1 | 1,2,5,8-10 | {1,2,5,8,9,10}
2 | 1,2,3 | {1,2,3}
3 | 1-3 | {1,2,3}
4 | 1-3, 4-5 | {1,2,3,4,5}
5 | 1-2,2-3 | {1,2,3}
(5 rows)
这不会特别快,但可能没问题。如果没有,用 C 写一些更快的东西作为扩展,或者 plperl 或其他东西。
要了解发生了什么,请阅读 PostgreSQL 手册部分:
GROUP BY
和聚合- 聚合函数,特别是
array_agg
DISTINCT
作为聚合限定符- PostgreSQL 数组,我在这里用作中间状态和结果
generate_series
函数regexp_split_to_table
和regexp_split_to_array
函数LATERAL
查询,此处隐式使用这些查询,因为一个函数使用连接列表中另一个函数的结果。
以上示例仅适用于 PostgreSQL 9.2 及更新版本。如果您使用的是旧版本,则必须使用嵌套子查询层来解决缺少 LATERAL
的问题。