0

ツリー ノードのすべての子を返すこの関数があります。

CREATE OR REPLACE FUNCTION fn_category_get_childs_v2(id_pai integer)
RETURNS integer[] AS
$BODY$

DECLARE

ids_filhos integer array;


BEGIN

SELECT array ( 

SELECT category_id FROM category WHERE category_id IN (
(WITH RECURSIVE parent AS
(
    SELECT category_id , parent_id  from category WHERE category_id = id_pai
    UNION ALL 
    SELECT t.category_id , t.parent_id FROM parent
    INNER JOIN category t ON parent.category_id =  t.parent_id
)

SELECT category_id FROM  parent
WHERE category_id <> id_pai
) )


 ) into ids_filhos; 

return ids_filhos;

END;

次のようなselectステートメントで使用したいと思います。

select * 
from teste1_elements 
where category_id in (select * from fn_category_get_childs_v2(12))

私も同じ結果でこの方法を試しました:

select * 
from teste1_elements
where category_id=any(select * from fn_category_get_childs_v2(12)))

しかし、次のエラーが表示されます。

ERROR:  operator does not exist: integer = integer[]
LINE 1: select * from teste1_elements where category_id in (select *...
                                                    ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.

関数は整数配列を返しますが、それが問題ですか?

 SELECT * from fn_category_get_childs_v2(12)

次の配列 ( integer[])を取得します。

 '{30,32,34,20,19,18,17,16,15,14}'
4

2 に答える 2

2

関数は整数配列を返します、それは問題ですか?

はい。通常、使用するwhere category_id in (select * from fn_category_get_childs_v2(12))場合は、関数が配列ではなく行のセットを返すようにします。何かのようなものRETURNS SETOF integer

マニュアルの例が役立つ場合があります。

既存の関数を使用することもできますが、配列と比較するには別の構文を使用する必要があります。

これはもっと近いはずだと思います:

select * 
from teste1_elements 
where category_id = any(fn_category_get_childs_v2(12))
于 2012-09-10T16:59:50.117 に答える
1

コアの再帰WITHクエリは、次のように単純化できます。

WITH RECURSIVE children AS (
    SELECT category_id
    FROM   category
    WHERE  parent_id = id_pai

    UNION ALL 
    SELECT c.category_id
    FROM   children ch
    JOIN   category c ON c.parent_id = ch.category_id
    )
SELECT *
FROM   children;

より短く、よりクリーンに、より速く。
それを関数にラップしたい場合は、この単純なケースではplpgsql 関数の代わりにプレーンなSQL 関数を使用します。

CREATE OR REPLACE FUNCTION f_cat_children(_id_pai int, OUT category_id int)
  RETURNS SETOF int
  LANGUAGE SQL AS
$func$
   WITH RECURSIVE children AS (
      SELECT c.category_id
      FROM   category c
      WHERE  c.parent_id = $1

      UNION ALL 
      SELECT c.category_id
      FROM   children ch
      JOIN   category c ON c.parent_id = ch.category_id
      )
   SELECT *
   FROM   children;
$func$;

OUTパラメータを使用して列名を結果の列に割り当てcategory_idます - 後で結合を簡素化します。これは体のいたるところに見られることに注意してください。c.category_idそのため、列を明確にするために列を表修飾する必要があります。

引数名と定位置パラメーター

コメントへの返信:
PostgreSQL 9.2 (昨日リリース) 以降、名前または位置パラメータ ( $1$2、 ...) で引数を参照できます。ここでマニュアルを引用します:

SQL 関数の引数は、名前または番号を使用して関数本体で参照できます。両方の方法の例を以下に示します。

ただし、関数本体で位置パラメータのみが理解される PostgreSQL 9.1 以前の場合はそうではありません。それに伴い関数を修正しました。

PL/pgSQL 関数は、バージョン 8.0 で導入されて以来、引数名を理解しています。

結果のクエリは、次JOINの代わりに構文を使用すると簡単になりますIN

SELECT t.* 
FROM   teste1_elements t
JOIN   f_cat_children(12) USING (category_id)

または、関数なしで単一のクエリですべてを実行します。

WITH RECURSIVE children AS (
    SELECT category_id
    FROM   category
    WHERE  parent_id = id_pai

    UNION ALL 
    SELECT c.category_id
    FROM   children ch
    JOIN   category c ON c.parent_id = ch.category_id
    )
SELECT t.*
FROM   children
JOIN   teste1_elements t USING (category_id);

まだ少し速くなるはずです。

于 2012-09-10T19:41:33.237 に答える