1

我有一张 Maven 项目表。每个项目都有许多参数和一个版本号。

当我从表中选择时,我应该只获得最高版本,但由于 Maven 版本的外观,这很棘手。这是我到目前为止的查询:

select id, group_id as group, artifact_id as artifact
from (
   select 
     p.group_id,
     p.artifact_id,
     p.id,
     rank() over (partition by p.group_id, p.artifact_id order by p.version desc)
   from projects p
   ) as ranked
   where ranked.rank = 1

这不会给出最高版本,因为版本不遵循字母数字顺序。
版本格式在此处描述

要点是一个版本可以是1.2.3-SNAPSHOT,其中1(major), 2(minor), 3(incremental) 是数字并且应该这样排序并且SNAPSHOT(qualifier) 是一个字符串。如果版本不遵循此格式,则应将其视为字符串。

这在 PostgreSQL 中可行吗?

4

1 回答 1

2

解析字符串。喜欢:

SELECT version
      ,substring(version, '^(\d+)')::int AS major
      ,substring(version, '^\d+\.(\d+)')::int AS minor
      ,substring(version, '^\d+\.\d+\.(\d+)')::int AS incremental
      ,substring(version, '-(.+)$') AS qualifier
FROM  (
   VALUES
     ('1.2.3-SNAPSHOT')
   , ('2-FOO')
   , ('2-BAR')
   , ('2.1-BAR')
   , ('13.5.6-SNAPSHOT')
   , ('13.11.11-SNAPSHOT')
   ) x(version)
ORDER  BY major NULLS LAST
        , minor NULLS FIRST
        , incremental NULLS FIRST
        , qualifier NULLS FIRST;

->SQLfiddle 演示。

  • substring(version, '^(\d+)').. 使用substring()正则表达式模式进行解析。
    ^.. 字符串开头
    ().. 捕获括号
    \d.. 类数字速记
  • substring(version, '^(\d+)')::int.. 转换为整数以像数字一样排序
  • major NULLS LAST.. 没有编号的版本排在最后(我的假设)。
  • minor NULLS FIRST..2来之前2.1
  • NULLS LAST是默认值,ORDER BY可以省略。

您可以直接使用这些表达式ORDER BY。只是为了更好的可读性而演示。

先进的解决方案

对于更复杂的规则,您可能需要使用regexp_matches()

SELECT *, part[1] AS p1, part[2] AS p2, part[3] AS p3, part[4] AS p4
        , part[5] AS p5, part[6] AS p6, part[7] AS p7
FROM  (
   SELECT test_id, version, regexp_matches(version
           , '^(?:(\d+)(\w*)\.?(\d*)(\w*)\.?(\d*)(\w*))?(?:\-*(\w+))?') AS part
   FROM  (
      VALUES
        (1, '1.2.3-SNAPSHOT')
      , (2, '2-FOO')
      , (3, '2-BAR')
      , (4, '2.1-BAR')
      , (5, '13.5.6-SNAPSHOT')
      , (6, '13.11.11-SNAPSHOT')
      , (7, '13.11a.11-SNAPSHOT')
      , (8, '13.11b.11')
      , (9, 'Test')
      , (10, 'TEST2')
      , (11, '1a')
      , (12, '1a.1a.1a-foo')
      , (13, '1a.1a.1b-foo')
      , (14, 'sp9d8hgf')
      , (15, '2a-BAR')
      , (16, '2.1a-BAR')
      , (17, '2.1ab-BAR')
      , (18, 'incorrect1.2-foo')
      ) x(test_id, version)
   ) sub
ORDER  BY NULLIF(part[1],'')::int NULLS LAST
        , part[2] NULLS FIRST
        , NULLIF(part[3],'')::int NULLS FIRST
        , part[4] NULLS FIRST
        , NULLIF(part[5],'')::int NULLS FIRST
        , part[6] NULLS FIRST
        , part[7] NULLS FIRST;

-> SQL小提琴

这涉及您评论中的所有附加规则

regexp_matches()是一个强大的工具,但你需要对正则表达式有基本的了解。如有疑问,请测试。
特别注意:

  • 不加g开关。更多在这里。
  • ()请注意捕获括号和非捕获括号之间的区别(:?)
  • NULLIF(part[1],'')::int.. 不匹配项在数组中列为空字符串。需要在转换为NULL之前转换为integer
于 2013-09-12T22:31:54.220 回答