Maven版本订购

时间:2013-09-12 22:18:17

标签: sql regex postgresql maven natural-sort

我有一个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

由于版本不遵循字母数字排序,因此未提供最高版本 The version format is described here

要点是版本可以是1.2.3-SNAPSHOT,其中1(主要),2(次要),3(增量)是数字,应该订购因此,SNAPSHOT(限定符)是一个字符串。如果版本不遵循此格式,则应将其视为字符串。

这在PostgreSQL中是否可行?

1 个答案:

答案 0 :(得分: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 demo.

  • substring(version, '^(\d+)') ..使用substring() with regular expression patterns进行解析 ^ ..字符串的开头
    () ..捕捉括号
    \d ..班级简写
  • substring(version, '^(\d+)')::int ..转换为整数以排序为数字
  • major NULLS LAST ..没有编号的版本最后(我的假设)。
  • minor NULLS FIRST .. 2出现在2.1
  • 之前
  • NULLS LASTORDER 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;

-> SQLfiddle

这涉及all additional rules from your comment

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

  • 未添加g开关。 More here.
  • 请注意捕获()和非捕获括号(:?)之间的区别。
  • NULLIF(part[1],'')::int ..不匹配在数组中列为空字符串。在转换为NULL
  • 之前,需要转换为integer