我有一个总是返回单个数组的SQL子查询。我希望我的外部查询过滤该数组中值的位置。我期望工作的任何东西都是为此而努力。
设置最小测试:
CREATE TABLE test (num int);
INSERT INTO test (num) values (1);
INSERT INTO test (num) values (2);
我的尝试查询,应返回两行," 1"和" 2":
SELECT * FROM test WHERE num = ANY(SELECT array_agg(num) from test);
当然...... ERROR: operator does not exist: integer = integer[]
。子查询返回一行包含数组,我需要获取数组。
也尝试了这个没有成功:
SELECT * FROM test WHERE num = ANY((SELECT array_agg(num) from test)[0]);
我得到ERROR: op ANY/ALL (array) requires array on right side
。这对我没有意义,但我不是专家。
我应该在这做什么?
答案 0 :(得分:4)
第一个错误是由于PostgreSQL看到了
num = ANY(SELECT array_agg(num) from test)
作为
的一种形式expression operator ANY (subquery)
而不是你想要的那个:
expression operator ANY (array expression)
因此,它会尝试将num
与子查询返回的任何 ROW 进行比较(在您的示例中返回单行ARRAY[1,2]
),而不是每个元素数组(因此你得到operator does not exist: integer = integer[]
错误)。有关详细信息,请参阅the documentation。
第二个错误只是来自[0]
访问integer[]
的元素的事实,因此返回integer
。由于右操作数必须是一个数组(或子查询,但PostgreSQL不能在这里看到一个),PostgreSQL返回ERROR: op ANY/ALL (array) requires array on right side
。
(顺便说一句,数组在PostgreSQL中基于1,而不是从0开始。)
如果您确定您的函数将始终返回单个数组,那么您只需强制Postgre查看SELECT array_agg(num) from test
作为integer[]
:
SELECT * FROM test
WHERE num = ANY((SELECT array_agg(num) from test)::integer[]);
┌─────┐
│ num │
├─────┤
│ 1 │
│ 2 │
└─────┘
(2 rows)
但请注意,如果您的函数返回多个数组,则会出现错误(因为setof integer[]
不能被视为integer[]
):
SELECT * FROM test
WHERE num = ANY((SELECT array_agg(num) from test GROUP BY num)::integer[]);
ERROR: 21000: more than one row returned by a subquery used as an expression
LOCATION: ExecSetParamPlan, nodeSubplan.c:970
另一种解决方案是使用unnest
函数将数组转换为一组整数,使用expression operator ANY (subquery)
形式。即使你的函数返回多个数组,这也会有效,尽管它比上一个查询慢一点。
SELECT *
FROM test
WHERE num = ANY(
SELECT unnest(sub.array_agg)
FROM (
SELECT array_agg(num) FROM test GROUP BY num -- GROUP BY num to show off the multiple array scenario
) AS sub
);
┌─────┐
│ num │
├─────┤
│ 1 │
│ 2 │
└─────┘
(2 rows)
答案 1 :(得分:1)
@Marth already explained详细信息和ANY
构造的一些应用程序。密切相关:
有一个更简单的变体:在FROM
子句中使用子查询作为派生表,在加入中使用子查询:
SELECT t.*
FROM test t
JOIN (SELECT array_agg(num) arr FROM test) a ON t.num = ANY(a.arr);
如果子选择应返回多行(每个都有一个数组),这甚至可以工作。您获得 test
中与该数组的任何元素相匹配的每一行,但您只能 一次 。对于数组“{1,1,2}”,您将获得与“{1,2}”相同的两个行。
或 unnest()
和加入到没有ANY
的未加网元素。方便地使用相同的列名称并与USING
子句连接以合并已连接的列。然后,您可以SELECT *
获取仅test
的行:
SELECT *
FROM test t
JOIN unnest((SELECT array_agg(num) arr FROM test)) num USING (num);
这里为数组的每个元素得到一行,所以你得到三个结果行为'{1,1,2}'。
(SELECT array_agg(num) arr FROM test)
只是用于概念验证的虚拟子查询。但至少应该提到一次:如果可能的话,不要首先聚合,那么你不必在以后再删除。像:
SELECT *
FROM test t
JOIN (SELECT num FROM test) t1 USING (num);