简体   繁体   English

Postgres:使用数组的“递归”查询

[英]Postgres: “Recursive” query with Array

I have a database (that I can't change) one table looks like that: 我有一个数据库(无法更改),一个表如下所示:

| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1          | 711        | {4}                  |
| 2          | 712        | {6}                  |
| 3          | 788        |                      |
| 4          | 799        | {7}                  |
--------------------------------------------------

Now I try to define one Query that as first row the data with ID = 1 and as next rows, all data with the ID that are in the integer array next ( {4} ) so that my query returns: 现在我尝试定义一个查询,作为第一行与数据ID = 1个作为下一个行,与所有的数据ID是整数数组中next{4}使得我的查询返回:

| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1          | 711        | {4}                  |
| 4          | 799        | {7}                  |
--------------------------------------------------

But then stops, so it only results the element with the specified ID and it's next elements. 但是随后停止,因此它只会生成具有指定ID的元素及其next元素。

I tried sth. 我尝试过…… like this, but I can't get it to work: 像这样,但我无法使它工作:

SELECT * FROM tablenm WHERE ID = ANY(SELECT next FROM tablenm WHERE ID = 1) AND ID = 1

The current Workaround I use is to first use this query: 我当前使用的解决方法是首先使用此查询:

SELECT * FROM tablenm WHERE ID = 1

And then for each element in the Array I run the same query with the ID s in a loop programmatically, but this looks like a dirty hack and I hope there is a solutions for this with 1 SQL statement. 然后,对于数组中的每个元素,我都以编程方式在循环中运行ID s的相同查询,但这看起来像是一堆肮脏的东西,我希望有1条SQL语句可以解决此问题。

This doesn't require recursion, just array un-nesting. 这不需要递归,只需取消数组嵌套即可。

This should work: 这应该工作:

select * from tablename where id=1
UNION ALL
select * from tablename where id
  in (select unnest(next) from tablename where id=1);

You can use = ANY(array) in the JOIN condition: 您可以在JOIN条件中使用= ANY(array)

SELECT t2.*
FROM   tbl t1
JOIN   tbl t2 ON t2.id = ANY(t1.next)
              OR t2.id = t1.id  -- add first row
WHERE  t1.id = 1                -- enter id to filter on once
ORDER  BY (t2.id <> t1.id);     -- "first row the data with ID = ?"

Should be fastest. 应该最快。
As @Daniel explained, this form (like your query) includes the first row only once . 作为@Daniel解释说, 这种形式(如您的查询)包括只有一次的第一行。

If you want a "shorter query": 如果要“更简短的查询”:

SELECT t2.*
FROM   tbl t1
JOIN   tbl t2 ON t2.id = ANY(t1.next || t1.id) -- append id to array
WHERE  t1.id = 1;  -- not sure if you need ORDER BY

Shorter, but not faster than the first form, because this will be expanded to an equivalent of the first form internally. 比第一种形式更短但不快,因为它将在内部扩展为第一种形式的等效形式。 Test performance with EXPLAIN ANALYZE . EXPLAIN ANALYZE测试性能。

It should be noted that next can even be NULL , because: 应该注意, next甚至可以为NULL ,因为:

SELECT NULL::int[] || 5  --> '{5}'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM