0

「buildid」という列を持つ「App_build」、「Server_build」というテーブルがいくつかあり、多数のレコードが含まれています。すなわち:

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')すなわち:

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

SQL は初めてなので、開始方法がわかりません。分割コマンドを使用してから関数を使用できると思いますが、どこから開始すればよいかわかりません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 では バックスラッシュは 1 つだけstandard_conforming_strings = ONです。
    + .. 1 つ以上の先行原子。 $ .. 最後の文字として: 文字列の末尾に固定されます。

    より安価で正確な方法があるかもしれません。形式を適切に指定していません。

  • GROUP BYwithORDER BYが最初に出現する前の文字列をアプリ名として抽出し、グループ化して並べ替えます。正規表現は次のように説明しました。_substring()

    ^.. 最初の文字として: 検索式を文字列の先頭にアンカーします。.. 文字クラス: ではない
    [^_]任意の文字。 _

    と同じ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 に答える