我有两列,id integer
和version text
。我试图将version
中的字符串转换为整数,以便我可以选择id的最大(最新)版本。
但是,id
的第一个实例将自己存储为version
。例如:
id | version
---+--------
10 | '10'
而不是:
id | version
---+--------
10 | '10-0'
其他行遵循约定ID:10,版本:10-1。等
我怎样才能做到这一点?我已尝试split_part()
并投射为int
。但是,split_part(version, "-", 2)
将返回看起来像空字符串的内容。我尝试使用COALESCE(splitpart..., '0')
运行此操作但无效,因为它尝试读取字段索引2返回的空字段。
答案 0 :(得分:2)
要绕过没有连字符的版本字符串,可以使用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;
在这里演示:
答案 1 :(得分:2)
split_part()
返回空字符串(''
) - 而不是NULL
- 当要返回的部分为空或不存在时。这就是为什么COALESCE
在这里没有的原因。并且空字符串(''
)没有表示为integer
值,因此在尝试强制转换时会抛出错误。
在演示之前,此示例中的最短路径应为GREATEST(split_part( ... ) , '0')
,因为空字符串在任何其他非空字符串之前排序,甚至是NULL(在任何语言环境中)。然后使用DISTINCT ON ()
获取"最大" version
每个id
。
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
(按降序排序)进行排序:< / p>
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
相关:
答案 2 :(得分:1)
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)