使用 split_part 后替换空字段中的值
Substituting value in empty field after using split_part
我有两列,id integer
和 version text
。我正在尝试将 version
中的字符串转换为整数,以便我可以 select id 的最大(最新)版本。
但是,id
的第一个实例将自己存储为 version
。示例:
id | version
---+--------
10 | '10'
相对于:
id | version
---+--------
10 | '10-0'
其他行遵循约定 ID:10,版本:10-1。等等
我怎样才能做到这一点?我试过 split_part()
并转换为 int
。然而,split_part(version, "-", 2)
将 return 看起来像一个空字符串。我已经尝试 运行 使用 COALESCE(splitpart..., '0')
无济于事,因为它试图读取由字段索引 2 编辑的空字段 return。
要避开没有连字符的版本字符串,您可以使用 CASE
表达式:
CASE WHEN version LIKE '%-%'
THEN SPLIT_PART(version, '-', 2)::int
ELSE 0 END
基本思想是在存在连字符时使用版本号,转换为 int,否则如果没有连字符则假定版本为零。
解决了这个障碍后,您的查询现在就减少为 ROW_NUMBER()
查询。在这里,分区是 id
,并且使用上面的 CASE
表达式给出版本的顺序。
SELECT
t.id, t.version
FROM
(
SELECT
id,
CASE WHEN version LIKE '%-%'
THEN version
ELSE version || '-0' END AS version,
ROW_NUMBER() OVER (PARTITION BY id
ORDER BY
CASE WHEN version LIKE '%-%'
THEN SPLIT_PART(version, '-', 2)::int
ELSE 0 END DESC) rn
FROM yourTable
) t
WHERE t.rn = 1
ORDER BY t.id;
此处演示:
使用组合coalesce() and nullif(),例子:
with my_table(version) as (
values
('10'), ('10-1'), ('10-2')
)
select
version,
split_part(version, '-', 1)::int as major,
coalesce(nullif(split_part(version, '-', 2), ''), '0')::int as minor
from my_table
version | major | minor
---------+-------+-------
10 | 10 | 0
10-1 | 10 | 1
10-2 | 10 | 2
(3 rows)
split_part()
returns the empty string (''
) - not NULL
- when the part to be returned is empty or non-existent. That's why COALESCE
在这里什么都不做。并且空字符串 (''
) 没有表示为 integer
值,因此在尝试转换它时会抛出错误。
此示例中最短的方法应该是 GREATEST(split_part( ... ) , '0')
转换之前,因为空字符串排在任何其他非空字符串甚至 NULL(在任何语言环境中)之前。然后使用 DISTINCT ON ()
为每个 id
.
获取带有 "biggest" version
的行
测试设置
CREATE TABLE tbl (
id integer NOT NULL
, version text NOT NULL
);
INSERT INTO tbl VALUES
(10, '10-2')
, (10, '10-1')
, (10, '10') -- missing subversion
, (10, '10-111') -- multi-digit number
, (11, '11-1')
, (11, '11-0') -- proper '0'
, (11, '11-') -- missing subversion but trailing '-'
, (11, '11-2');
解决方案
SELECT DISTINCT ON (id) *
FROM tbl
ORDER BY id, GREATEST(split_part(version, '-', 2), '0')::int DESC;
结果:
id | version
----+---------
10 | 10-111
11 | 10-2
或你可以也可以使用NULLIF
并使用NULLS LAST
(降序)排序:
SELECT DISTINCT ON (id) *
FROM tbl
ORDER BY id, NULLIF(split_part(version, '-', 2), '')::int DESC NULLS LAST;
同样的结果。
或更明确的CASE
声明:
CASE WHEN split_part(version, '-', 2) = '' THEN '0' ELSE split_part(version, '-', 2) END
dbfiddle here
相关:
- Order varchar string as numeric
- Select first row in each GROUP BY group?
- PostgreSQL sort by datetime asc, null first?
- How to convert empty to null in PostgreSQL?
我有两列,id integer
和 version text
。我正在尝试将 version
中的字符串转换为整数,以便我可以 select id 的最大(最新)版本。
但是,id
的第一个实例将自己存储为 version
。示例:
id | version
---+--------
10 | '10'
相对于:
id | version
---+--------
10 | '10-0'
其他行遵循约定 ID:10,版本:10-1。等等
我怎样才能做到这一点?我试过 split_part()
并转换为 int
。然而,split_part(version, "-", 2)
将 return 看起来像一个空字符串。我已经尝试 运行 使用 COALESCE(splitpart..., '0')
无济于事,因为它试图读取由字段索引 2 编辑的空字段 return。
要避开没有连字符的版本字符串,您可以使用 CASE
表达式:
CASE WHEN version LIKE '%-%'
THEN SPLIT_PART(version, '-', 2)::int
ELSE 0 END
基本思想是在存在连字符时使用版本号,转换为 int,否则如果没有连字符则假定版本为零。
解决了这个障碍后,您的查询现在就减少为 ROW_NUMBER()
查询。在这里,分区是 id
,并且使用上面的 CASE
表达式给出版本的顺序。
SELECT
t.id, t.version
FROM
(
SELECT
id,
CASE WHEN version LIKE '%-%'
THEN version
ELSE version || '-0' END AS version,
ROW_NUMBER() OVER (PARTITION BY id
ORDER BY
CASE WHEN version LIKE '%-%'
THEN SPLIT_PART(version, '-', 2)::int
ELSE 0 END DESC) rn
FROM yourTable
) t
WHERE t.rn = 1
ORDER BY t.id;
此处演示:
使用组合coalesce() and nullif(),例子:
with my_table(version) as (
values
('10'), ('10-1'), ('10-2')
)
select
version,
split_part(version, '-', 1)::int as major,
coalesce(nullif(split_part(version, '-', 2), ''), '0')::int as minor
from my_table
version | major | minor
---------+-------+-------
10 | 10 | 0
10-1 | 10 | 1
10-2 | 10 | 2
(3 rows)
split_part()
returns the empty string (''
) - not NULL
- when the part to be returned is empty or non-existent. That's why COALESCE
在这里什么都不做。并且空字符串 (''
) 没有表示为 integer
值,因此在尝试转换它时会抛出错误。
此示例中最短的方法应该是 GREATEST(split_part( ... ) , '0')
转换之前,因为空字符串排在任何其他非空字符串甚至 NULL(在任何语言环境中)之前。然后使用 DISTINCT ON ()
为每个 id
.
version
的行
测试设置
CREATE TABLE tbl (
id integer NOT NULL
, version text NOT NULL
);
INSERT INTO tbl VALUES
(10, '10-2')
, (10, '10-1')
, (10, '10') -- missing subversion
, (10, '10-111') -- multi-digit number
, (11, '11-1')
, (11, '11-0') -- proper '0'
, (11, '11-') -- missing subversion but trailing '-'
, (11, '11-2');
解决方案
SELECT DISTINCT ON (id) *
FROM tbl
ORDER BY id, GREATEST(split_part(version, '-', 2), '0')::int DESC;
结果:
id | version
----+---------
10 | 10-111
11 | 10-2
或你可以也可以使用NULLIF
并使用NULLS LAST
(降序)排序:
SELECT DISTINCT ON (id) *
FROM tbl
ORDER BY id, NULLIF(split_part(version, '-', 2), '')::int DESC NULLS LAST;
同样的结果。
或更明确的CASE
声明:
CASE WHEN split_part(version, '-', 2) = '' THEN '0' ELSE split_part(version, '-', 2) END
dbfiddle here
相关:
- Order varchar string as numeric
- Select first row in each GROUP BY group?
- PostgreSQL sort by datetime asc, null first?
- How to convert empty to null in PostgreSQL?