在自定义函数中使用 SQL 查询作为数组参数(输入)

Posted

技术标签:

【中文标题】在自定义函数中使用 SQL 查询作为数组参数(输入)【英文标题】:Use SQL query as array parameter (input) in custom function 【发布时间】:2016-12-29 16:28:58 【问题描述】:

我在 pl/pgsql 中创建了一个自定义函数,它的唯一输入是一个数组。我想将查询结果用作此自定义函数的输入,但似乎无法正确处理。我将使用一个更简单的函数作为示例,并且使用一个比我尝试用作输入的查询更简单的查询。

函数定义:

CREATE OR REPLACE FUNCTION bigger_than_ones(input_array int[])
returns SETOF int
AS
$$
DECLARE
  array_item int;
BEGIN
  FOREACH array_item in ARRAY input_array
  LOOP
    IF array_item > 1 THEN
      RETURN NEXT array_item;
    END IF;
  END LOOP;
END
$$ LANGUAGE plpgsql;

我有一个表,其列的数据类型与数组数据类型相同。在这种情况下是一个整数列:

SELECT * FROM my_table;
id | int_attribute
---+--------------
1  | 2
2  | 3
3  | 1
4  | 4
5  | 1
6  | 6
7  | 1
8  | 1
9  | 8

我想使用一个返回该数据类型的列的查询作为我的函数的输入。我已经尝试了一些变体,但没有任何运气:

SELECT * FROM bigger_than_ones(SELECT int_attribute FROM my_table);

返回:

result 
-------------
2
3
4
6
8

我使用类似结构函数的原因是因为我需要在我的代码中的多个位置计算来自多个表的合并时间范围(自定义类型)。我最好的想法是创建一个可以做到这一点的函数,无论我从哪里获取它,都将所有时间范围用作输入,这样我就不必每次都进行更复杂的查询。

对我缺少什么有什么想法吗?

【问题讨论】:

我不清楚您要通过查询实现什么。请edit您的问题并添加一些示例数据和基于该数据的预期输出。 Formatted 文本 请no screen shots 这不就是select int_attribute from my_table where int_attribute > 1吗? 你的函数需要一个数组。为什么你认为你可以(或应该)给它传递一个简单的整数值?你为什么要这样定义你的函数? 我知道示例中的函数不是很有用,很容易用简单的查询替换。我简化了原始函数,使其在 SO 上下文中可读。 您将问题简化到不再有意义的程度 【参考方案1】:

你发现的是一个ARRAY constructor,它不是一个操作符(也不是一个函数),而是一个SQL构造(一个SQL语法元素)。引用的答案使用了错误的术语(现已修复)。差异可能很重要。

SELECT * FROM bigger_than_ones(ARRAY(SELECT int_attribute FROM my_table));

您也可以使用基本的aggregate function array_agg(),它更容易集成到更复杂的查询中 - 但对于简单的情况来说速度较慢:

SELECT * FROM bigger_than_ones((SELECT array_agg(int_attribute) FROM my_table));

相关:

How to make an array from a SELECT returning more than one row

我假设您知道unnest()?它可以用来从根本上简化您的测试功能:

CREATE OR REPLACE FUNCTION bigger_than_ones(input_array int[])
  RETURNS SETOF int AS
$func$
   SELECT *
   FROM   unnest(input_array) elem
   WHERE  elem > 1;
$func$  LANGUAGE sql;

此外,通常有一种基于集合的优越方法来解决所有这些问题。 从一个集合构造一个数组只是为了将它传递给一个函数可能是不必要的复杂化。

【讨论】:

我不知道unnest() 看起来很有用,谢谢。我使用类似结构函数的原因是因为我需要在我的代码中的多个位置计算来自多个表的结果合并时间范围(自定义类型)。我最好的想法是创建一个可以做到这一点的函数,无论我从哪里获取它,都将其用作所有时间范围的输入,这样我就不必每次都进行更复杂的查询。抱歉,如果有些地方不够清楚,英语不是我的第一语言。 @shevia:在你更新之后,问题就很清楚了。实际上,比大多数人都清楚。一大遗漏:您的 Postgres 版本 - 应该在 每个 问题中声明。只是想提一下可能是一种更好的方法。也许不吧。也许是自定义聚合函数?或tstzrange(min(lower(...), max(upper(...))。您可能想问另一个问题,了解您的设置和要求的确切详细信息。【参考方案2】:

我终于在另一个 SO 问题中找到了解决方案:Store select query's output in one array in postgres

我可以按如下方式使用 array() 运算符:

SELECT * FROM bigger_than_ones(ARRAY(SELECT int_attribute FROM my_table));

得到了预期的输出。

【讨论】:

【参考方案3】:

您是否尝试过创建自定义类型?有数组和表等集合类型,也有类似于单行记录的对象类型。然后,您可以创建此自定义类型的变量以用作参数。

这是一个例子:

CREATE 或 REPLACE TYPE namearray AS VARRAY(3) OF VARCHAR2(10);

【讨论】:

这对 Postgres 无效

以上是关于在自定义函数中使用 SQL 查询作为数组参数(输入)的主要内容,如果未能解决你的问题,请参考以下文章

如何在用户定义的函数中将数据库列作为参数传递?

SQL Server存储过程中使用表值作为输入参数示例

sqlserver自定义函数里面 怎么循环查询多条结果集

使用“IN”命令将数组作为要在 SQL 查询中使用的参数传递

c# sql 参数数组 执行?

函数如何将数组或设置值作为 PostgreSQL 中用户定义函数的参数 (IN)