比较postgres中的软件版本

131*_*131 12 postgresql version plpgsql version-sort

有没有办法在postgres中比较软件版本(例如XYZ> ABC)?我正在搜索string/varchar或"version"类型的函数.

我发现了http://pgxn.org/dist/semver/doc/semver.html,但我正在寻找替代方案(不是那么容易部署..)

非常感谢.

Erw*_*ter 23

使用更便宜string_to_array().这里不需要昂贵的正则表达式:

SELECT string_to_array(v1, '.')::int[] AS v1
     , string_to_array(v2, '.')::int[] AS v2
     ,(string_to_array(v1, '.')::int[] > string_to_array(v2, '.')::int[]) AS cmp
FROM   versions;
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

  • @EricHu:你可能错过了演员`int []`.因此`1.10> 1.9`. (2认同)

Fab*_*tor 9

您可以将版本拆分为数组,然后进行数组比较.

select regexp_split_to_array(v1, '\.')::int[] v1, 
       regexp_split_to_array(v2, '\.')::int[] v2,
       regexp_split_to_array(v1, '\.')::int[] > regexp_split_to_array(v2, '\.')::int[] cmp
from versions;
Run Code Online (Sandbox Code Playgroud)

演示

  • 比较字符串数组并不比简单地比较字符串更好 - 你仍然会得到像''1.9'>'1.10'这样的东西.您可能希望将`split`输出转换为`int []`. (3认同)

小智 5

正如已经建议的,一种简单的方法是使用版本的数字格式。变量“server_version_num”包含版本的数字格式。

例如。

  • 版本 9.5.2 => 90502
  • 版本 9.6.0 => 90600
  • 版本 10.5 => 100500

    选择当前设置('服务器版本号')

返回一个可以轻松与另一个版本号进行比较的数字。


Uly*_* BN 5

进一步Erwin的回答,我们可以创建一个函数来将软件版本与需求进行比较(就像在ruby中一样)。我已经编写了一个函数来执行此操作,请使用它:

\n
SELECT semver_match(\'4.2.0\', \'>= 4.0\'); -- TRUE\n
Run Code Online (Sandbox Code Playgroud)\n

这是代码和测试:

\n
CREATE OR REPLACE FUNCTION semver_match(version text, req text) RETURNS boolean\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT\n    AS $$ \n    SELECT CASE\n    WHEN req LIKE \'~>%\' THEN\n        string_to_array(version, \'.\')::int[] >= string_to_array(substring(req from 4), \'.\')::int[]\n        AND\n        string_to_array(version, \'.\')::int[] <\n        -- increment last item by one. (X.Y.Z => X.Y.(Z+1))\n        array_append(\n            (string_to_array(substring(req from 4), \'.\')::int[])[1:(array_length(string_to_array(req, \'.\'), 1) - 1)], -- X.Y\n            (string_to_array(substring(req from 4), \'.\')::int[])[array_length(string_to_array(req, \'.\'), 1)] + 1 -- Z + 1\n        )\n WHEN req LIKE \'>=%\' THEN string_to_array(version, \'.\')::int[] >= string_to_array(substring(req from 4), \'.\')::int[]\n    WHEN req LIKE \'<=%\' THEN string_to_array(version, \'.\')::int[] <= string_to_array(substring(req from 4), \'.\')::int[]\n    WHEN req LIKE \'>%\' THEN string_to_array(version, \'.\')::int[] > string_to_array(substring(req from 3), \'.\')::int[]\n    WHEN req LIKE \'<%\' THEN string_to_array(version, \'.\')::int[] < string_to_array(substring(req from 3), \'.\')::int[]\n   WHEN req LIKE \'=%\' THEN \n        (string_to_array(version, \'.\')::int[])[1:array_length(string_to_array(substring(req from 3), \'.\'), 1)] = \n        string_to_array(substring(req from 3), \'.\')::int[]\n    ELSE NULL\n    END $$;\n\n-- tests.\nSELECT \n    ver,\n    req,\n    CASE WHEN semver_match(ver, req) = expected\n    THEN \'\xe2\x9c\x85\' ELSE \'\xe2\x9d\x8c\' END AS test_passed\nFROM (VALUES\n    (\'2.3\',   \'>= 2.3\',   TRUE),\n    (\'2.3.1\', \'> 2.3\',    TRUE),\n    (\'2.3.1\', \'< 2.3.2\',  TRUE),\n    (\'2.3.1\', \'~> 2.3.2\', FALSE),\n    (\'2.4.3\', \'~> 2.3.2\', FALSE),\n    (\'2.3.2\', \'~> 2.3.2\', TRUE),\n    (\'2.3.2\', \'= 2.3.2\',  TRUE),\n    (\'2.3.2\', \'= 2.3\',    TRUE),\n    (\'2.3.2\', \'= 2.4\',    FALSE)\n) AS _ (ver, req, expected)\n
Run Code Online (Sandbox Code Playgroud)\n

有关更多实现细节,请参阅我关于该主题的博文

\n