使用split_part后在空字段中替换值

时间:2017-08-19 00:48:17

标签: sql postgresql split natural-sort

我有两列,id integerversion 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返回的空字段。

3 个答案:

答案 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;

在这里演示:

Rextester

答案 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)

使用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)