简体   繁体   中英

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: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.

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.

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:

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 .

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 .

It should be noted that next can even be NULL , because:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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