1

Postgresql 8.4を入手しました

ユーザーテーブルがあります

user_id INT,
user_name VARCHAR(255),
user_email VARCHAR(255),
user_salt VARCHAR(255)

および 2 つの関数:

1 つSETOF:

CREATE FUNCTION test ()
  RETURNS SETOF "user"
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      *
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

1 つTABLE:

CREATE FUNCTION test ()
  RETURNS TABLE (id INT, name VARCHAR, email VARCHAR)
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

列の種類によってSETOF自動的に入力されますが、列名と結果で選択する列を設定できません。プレフィックスをTABLE切り捨てuser_て正確な列名を設定できますが、列の種類を手動で設定する必要があります。

両方の利点を得ることは可能ですか?

4

2 に答える 2

2

PostgreSQL (および一般的な SQL) での型処理は厳密です。RETURN関数の型を定義するのは難しい場合があります。プレーン SQL を使用した簡単なソリューションがあり
ます。

すべての列を選択して名前を変更します。

SELECT * FROM t AS t(id, name, email, salt);

いくつかの列を選択して名前を変更します。

SELECT user_id AS id, user_name AS name FROM t;

関数と組み合わせる

何らかの理由でサーバー側関数が必要な場合でも、これらの SQL 機能を関数と組み合わせることができます。tあなたの質問で定義されたようなテーブルとこの単純な関数を考えると:

CREATE OR REPLACE FUNCTION f_test()
  RETURNS SETOF t AS
$func$
SELECT * FROM t  -- do stuff here
$func$ LANGUAGE sql STABLE;

列の名前のみを変更するには (型を指定する必要はありません):

SELECT * FROM f_test() t(id, name, email, salt)

いくつかの列を選択して名前を変更します。

SELECT user_id AS id, user_name AS name FROM f_test() t;

これをさまざまなテーブルのさまざまな関数と組み合わせることができます:
PL/pgSQL 関数をリファクタリングして、さまざまな SELECT クエリの出力を返します。

しかし、ここで具体的にどの問題に取り組みたいのか、私にはよくわかりません。

アシデス

于 2013-07-04T15:17:57.360 に答える
1

ユーザー定義型に強く依存しているため、pl/pgsqlではこれが可能だとは思いません。悲しいことに、この言語は型の自動検出には十分にスマートではありません...私が使用する最初の可能な解決策は、少なくともテーブル列の型変更によってすべての関数を手動でリファクタリングする必要がないため、問題を部分的に解決すると思います.

1.) 列の種類を尋ねることで考えられる解決策:

CREATE FUNCTION test ()
  RETURNS TABLE (id "user".user_id%TYPE, name "user".user_name%TYPE, email "user".user_email%TYPE)
AS
  $BODY$
  BEGIN
    return QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

これにより、少なくともタイプは冗長ではありません。最高ではありませんが、許容範囲です。

2.) SETOF RECORD で可能な解決策:

CREATE FUNCTION test ()
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id AS id, "user".user_name AS name, "user".user_email AS email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

列タイプ定義リストがないと、次のエラーが発生しました。

エラー: 「レコード」を返す関数には列定義リストが必要です

したがって、次のように使用する必要があります。

SELECT * FROM test() AS (id INT, name VARCHAR, email VARCHAR);

これの代わりに:

SELECT * FROM test()

PHPクライアントによってすべての列を文字列で取得したため、列タイプの定義は役に立たない...このソリューションは、列タイプの定義なしで最適ですが、受け入れられません。

これを表のように使用できます。

CREATE FUNCTION test (OUT id "user".user_id%TYPE, OUT name "user".user_name%TYPE, OUT email "user".user_email%TYPE)
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

たとえば、すべてを TEXT に設定できます。

CREATE FUNCTION test (OUT id TEXT, OUT name TEXT , OUT email TEXT )
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id::TEXT , "user".user_name::TEXT , "user".user_email::TEXT 
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

これは機能しますが、これはタイプの自動検出とはほど遠いものであり、多くの冗長なテキスト コンバーター コードが生成されます...

3.) refcursor を使用した可能な解決策:

CREATE FUNCTION test ()
  RETURNS SETOF "user"
AS
  $BODY$
  DECLARE
    refc "user";
  BEGIN
    FOR refc IN 
      SELECT
        "user".user_id, "user".user_name, "user".user_email
      FROM
        "user"
    LOOP
        RETURN NEXT refc;
    END LOOP ;
    RETURN ;
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

これにより、不足している列にnull値が入力され、列に名前を付けることができず、SQLループが非常に遅くなります...したがって、これは受け入れられません。

refcursors には別の方法があります: refcursor 自体を返す方法ですが、通常の変数として使用できないため受け入れられません。カーソル名として文字列を指定する必要があります...ところで、refcursor 自体を使用することができませんでしたその結果、phpstorm が発生します。jdbc cursor not found エラーが発生しました。名前を間違って設定したのかもしれませんが、わかりません。これ以上努力する価値はないと思います。

于 2013-07-04T10:38:47.370 に答える