web-dev-qa-db-ja.com

plpgsqlを使用した再帰クエリ

ツリー構造のレコードから列のセットを再帰的に返すplpgsql関数を記述しようとしています。

データテーブルとデータをリンクするためのテーブルがあります。

DATATABLE
-----------
id integer
value text
info text

LINKTABLE
-----------
link integer
parent integer

私の考えは次の関数のようにすることでした:

CREATE OR REPLACE FUNCTION my_function(itemID integer)
  RETURNS TABLE(id integer, value text) AS
$BODY$
BEGIN    
    RETURN QUERY SELECT my_function(A.link) FROM linktable A, datatable B 
        WHERE A.parent = B.id AND B.id = itemID) C;

    RETURN QUERY SELECT id, value FROM datatable WHERE id = itemID;            
    RETURN;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

しかし、それは機能しません。最初のクエリでエラーが発生します。

エラー:クエリの構造が関数の結果のタイプと一致しません

私のJust-In-Brainコンパイラは問題を検出しないので、ここで何が問題になっていますか?

2
Chau

関数はまったく必要ありません。これは単一のSQLステートメントで実行できます。

with recursive tree as (id, parent) (
    select link as id, 
           parent
    from linktable
    where id = itemid

    union all

    select c.link as id,
           c.parent
    from linktable c
      join tree p on p.id = c.parent
) 
select dt.id, dt.value
from tree
  join datatable dt on dt.id = tree.id

再帰クエリの概要については、マニュアルを参照してください: http://www.postgresql.org/docs/current/static/queries-with.html

これをplpgsql関数で実行したい場合は、いくつかの変更を加えるだけでうまくいきます。

CREATE OR REPLACE FUNCTION my_function(itemID integer)
  RETURNS TABLE(id integer, value text) AS
$BODY$
BEGIN
    RETURN QUERY
    SELECT (my_function(A.link)).*
    FROM linktable A
    JOIN datatable B ON A.parent = B.id AND B.id = itemID;

    RETURN QUERY 
    SELECT d.id, d.value 
    FROM datatable d
    WHERE d.id = itemID;

END;
$BODY$
LANGUAGE plpgsql;
  • 指定したエラーについては、関数呼び出しを括弧で囲み、.*を後に追加します
  • 返されるテーブルにはdatatableと同じ列名があるため、2番目のクエリで列名を修飾する必要があります
  • 適切な構文にするために) Cを削除

とにかく、CTEの使用についてa_horse_with_no_nameに同意します。

1
dezso