2つのビュー間の結合を返したい状況があります。それはたくさんの列です。 SQLServerではかなり簡単でした。しかし、PostgreSQLでは結合を行います。 「列定義リストが必要です」というエラーが表示されます。
これを回避する方法はありますか?戻り列の定義を提供したくありません。
CREATE OR REPLACE FUNCTION functionA(username character varying DEFAULT ''::character varying, databaseobject character varying DEFAULT ''::character varying)
RETURNS SETOF ???? AS
$BODY$
Declare
SqlString varchar(4000) = '';
BEGIN
IF(UserName = '*') THEN
Begin
SqlString := 'select * from view1 left join ' + databaseobject + ' as view2 on view1.id = view2.id';
End;
ELSE
Begin
SqlString := 'select * from view3 left join ' + databaseobject + ' as view2 on view3.id = view2.id';
End;
END IF;
execute (SqlString );
END;
$BODY$
マニュアル PL/pgSQLのすべての基本があります。基本的に、あなたが持っているものは単純化/消毒することができます:
_CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
RETURNS ???? AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ('SELECT * FROM %s v1 LEFT JOIN %I v2 USING (id)'
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END, databaseobject);
END
$func$ LANGUAGE plpgsql;
_
_BEGIN .. END
_ in the function body の追加のインスタンスは必要ありませんが、独自のスコープで別のコードブロックを開始する場合を除きます。
標準のSQL連結演算子は_||
_です。 _+
_は、以前のベンダーの「創造的な」追加です。
二重引用符で囲まない限り、 CaMeL-ケース識別子 を使用しないでください。まったく使用しないことをお勧めします。
varchar(4000)
も、SQLServerの特定の制限に合わせて調整されています。このデータ型には、Postgresではパフォーマンス上の利点はまったくありません。実際に4000文字の制限が必要な場合にのみ使用してください。ここでは、変数がまったく必要ないことを除いて、 text
-を使用します。機能を簡略化しました。
format()
をまだ使用していない場合は、 こちらのマニュアルを参照してください 。
さて、実際の質問です。SQLでは関数が明確に定義された型を返す必要があるため、動的クエリの戻り値の型は少し注意が必要です。返す列定義リストと一致するテーブル、ビュー、または複合型がデータベースにすでにある場合は、次のように使用できます。
_CREATE FUNCTION foo()
RETURNS SETOF my_view AS
...
_
タイプを作成しながら作成する場合は、匿名レコードを返すことができます。
_CREATE FUNCTION foo()
RETURNS SETOF record AS
...
_
または、列定義リストに(最も単純な)_RETURNS TABLE
_を提供します。
_CREATE FUNCTION foo()
RETURNS TABLE (col1 int, col2 text, ...) AS
...
_
匿名レコードの欠点:呼び出しごとに列定義リストを提供する必要があるため、これを使用することはほとんどありません。
そもそも_SELECT *
_は使いません。列の明確なリストを使用して、それに応じて戻りタイプを返し、宣言します。
_CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
RETURNS TABLE(col1 int, col2 text, col3 date) AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ('SELECT v1.col1, v1.col2, v2.col3
FROM %s v1 LEFT JOIN %I v2 USING (id)$f$
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END, databaseobject);
END
$func$;
_
完全に動的なクエリの場合、最初はプレーンSQLクエリを使用します。関数ではありません。
より高度なオプションがありますが、最初に基本を学ぶ必要があるかもしれません。