我有许多表'App_build','Server_build',其中包含一个名为'buildid'的列,它包含大量记录。即:
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)
的函数,即getmax('App_build')
这将返回仅列出最高值的记录集。即:
buildid
--------
Application1_BLD_03
Application2_BLD_01
Application3_BLD_02
Application4_BLD_03
我是SQL的新手,所以我不知道如何开始 - 我想我可以使用split命令然后使用MAX
函数,但我不知道从哪里开始。
任何帮助都会很棒。
答案 0 :(得分:2)
假设当前版本PostgreSQL 9.2缺乏信息。
简单查询可能如下所示:
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+$'
以4个整数除以buildid
的结尾排除_
。
\d
..数字的字符类简写。在standard_conforming_strings = ON
的现代PostgreSQL中只有一个反斜杠\
+
..前面原子中的一个或多个。
$
..作为最后一个字符:锚定在字符串的末尾。
可能有更便宜/更准确的方式,您没有正确指定格式。
GROUP BY
和ORDER BY
在第一次出现_
之前提取字符串,并将substring()
作为应用名称进行分组和排序。正则表达式解释说:
^
..作为第一个字符:锚点搜索表达式以开始字符串。
[^_]
..字符类:不 _
的任何字符。
与split_part(buildid, '_', 1)
相同。但split_part()
可能会更快..
如果要编写表名可变的函数,则需要动态SQL 。这是一个带有EXECUTE
的plpgsql函数:
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"');
有关the object identifier class regclass
的更多信息,请参阅此相关问题:
Table name as a PostgreSQL function parameter
答案 1 :(得分: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