0

我有许多表“App_build”、“Server_build”,其中有一列名为“buildid”,它包含大量记录。IE:

buildid
-----------
Application1_BLD_01
Application1_BLD_02
Application1_BLD_03
Application2_BLD_01
Application3_BLD_01
Application3_BLD_02
Application4_1_0_0_1 - old format to be disregarded
Application4_1_0_0_2
Application4_BLD_03

我想编写一个名为getmax(tablename)ie的函数getmax('App_build') ,它将返回一个仅列出最高值的记录集。IE:

buildid
--------
Application1_BLD_03
Application2_BLD_01
Application3_BLD_02
Application4_BLD_03

我是 SQL 新手,所以不知道如何开始 - 我想我可以使用 split 命令然后使用MAX函数,但我不知道从哪里开始。

任何帮助都会很棒。

4

2 回答 2

2

由于缺少信息,假设当前版本为 PostgreSQL 9.2。

纯 SQL

简单的查询可能如下所示:

SELECT max(buildid)
FROM   app_build
WHERE  buildid !~ '\d+_\d+_\d+_\d+$'  -- to exclude old format
GROUP  BY substring(buildid, '^[^_]+')
ORDER  BY substring(buildid, '^[^_]+');
  • 条件使用WHERE了正则表达式:

    buildid !~ '\d+_\d+_\d+_\d+$'
    

    不包括buildid以 4 个整数除以_.

    \d.. 数字的字符类简写。\现代 PostgreSQL 中 只有一个反斜杠和standard_conforming_strings = ON.
    + .. 1 个或多个前面的原子。 $ .. 作为最后一个字符:锚定到字符串的末尾。

    可能有更便宜/更准确的方法,您没有正确指定格式。

  • GROUP BYORDER BY提取第一次出现_withsubstring()作为应用程序名称之前的字符串以进行分组和排序。正则表达式解释:

    ^.. 作为第一个字符:将搜索表达式锚定到字符串的开头。
    [^_].. 字符类:任何不是 _.

    split_part(buildid, '_', 1). 但split_part()可能更快..

功能

如果要编写表名可变的函数,则需要动态 SQL。这是一个 plpgsql 函数EXECUTE

CREATE OR REPLACE FUNCTION getmax(_tbl regclass) 
  RETURNS SETOF text AS
$func$
BEGIN

RETURN QUERY
EXECUTE format($$
   SELECT max(buildid)
   FROM   %s
   WHERE  buildid !~ '\d+_\d+_\d+_\d+$'
   GROUP  BY substring(buildid, '^[^_]+')
   ORDER  BY substring(buildid, '^[^_]+')$$, _tbl);

END
$func$ LANGUAGE plpgsql;

称呼:

SELECT * FROM getmax('app_build');

或者,如果您实际上是在使用混合大小写标识符

SELECT * FROM getmax('"App_build"');

->SQLfiddle 演示。

有关此相关问题中对象标识符类 的更多信息:表名作为 PostgreSQL 函数参数regclass

于 2013-03-16T17:09:02.330 回答
0

你想要的是一个 groupwise_max。它可以完成,MAX()但通常的方法是左连接:

SELECT b1.buildid
FROM builds AS b1
LEFT JOIN builds AS b2 ON 
split_part(b1.buildid, '_', 1)=split_part(b2.buildid, '_', 1)
AND
split_part(b1.buildid, '_', 3)::int<split_part(b2.buildid, '_', 3)::int
WHERE b2.buildid IS NULL;

但是由于您使用的是PG,因此可以使用DISTINCT ON ()

SELECT DISTINCT ON (split_part(buildid, '_', 1)) buildid
FROM builds 
ORDER BY split_part(buildid, '_', 1),split_part(buildid, '_', 3)::int DESC

http://sqlfiddle.com/#!12/308bf/9

于 2013-03-16T17:01:32.997 回答