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 * 
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;

更短,更清洁,更快。
如果你想把它包装成一个函数,对于这个简单的例子,我会使用一个普通的SQL 函数而不是一个plpgsql 函数:

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 回答