Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL: Loop Until a Condition is True

I am trying to write a query which "loops" through a database starting at a specified value until a condition is true. For example, suppose I have the following entries in TABLE example:

id, parent, cond
1,        , True
2, 1      , False
3, 1      , False
4, 2      , False
... ... ...

I want a query which takes as input (for instance) 4, and will return the values of 2 and 1. The process being that the query matches the id, and if cond==False, will look at the parent (id = 2). Since cond = False in the second row, the "parent" id will be selected (1). Looking at the first row now, since cond=True, the LOOP ends and returns 1 and 2.

I know that the query

SELECT parent FROM example WHERE id = 4;

will produce the parent id 2.

So my futile attempt at creating a LOOP:

WHILE (SELECT cond FROM example) = False
LOOP SELECT parent FROM example WHERE id = 4 
END LOOP;

First, this produces an error ("syntax error at or near 'while'"). Second, I don't know how to update the "id" after each iteration.

In a programming language like Python, I might use a variable initialized to 4 and then update it with each iteration...not sure how to do the equivalent in Postgres.

Let me know if you have any questions or require additional information. Thanks!

like image 921
David C Avatar asked Aug 07 '12 06:08

David C


People also ask

Do while loops PostgreSQL?

The PostgreSQL WHILE LOOP evaluates the condition defined to decide whether the loop should be terminated or continued for execution. If the condition defined with PostgreSQL WHILE LOOP evaluates to true, then the body of WHILE LOOP or code statements are written inside the PostgreSQL WHILE LOOP is executed.

How do I create a loop in PostgreSQL?

For loop to iterate over the result set of a dynamic query The syntax of the for loop statement to iterate over a result set of a dynamic query: [ <<label>> ] for row in execute query_expression [ using query_param [, ... ] ] loop statements end loop [ label ];

What is do $$ in PostgreSQL?

In PostgreSQL, the dollar-quoted string constants ($$) is used in user-defined functions and stored procedures. In PostgreSQL, you use single quotes for a string constant like this: select 'String constant';

What is coalesce in PostgreSQL?

The COALESCE function returns the first of its arguments that is not null. Null is returned only if all arguments are null. It is often used to substitute a default value for null values when data is retrieved for display, for example: SELECT COALESCE(description, short_description, '(none)') ...


1 Answers

Your thinking is wrong for SQL. Don't think in terms of loops and conditions and variables; instead, think about how to describe the data you want. The tricky part is that you want the query to refer to its own results and that's what recursive CTEs are for:

The optional RECURSIVE modifier changes WITH from a mere syntactic convenience into a feature that accomplishes things not otherwise possible in standard SQL. Using RECURSIVE, a WITH query can refer to its own output.

You're looking for something like this:

with recursive path as (
    select id, parent from T where id = 4
    union all
    select t.id, t.parent from T t join path p on t.id = p.parent
)
select id, parent
from path

That will give you this:

 id | parent 
----+--------
  4 |      2
  2 |      1
  1 |       

and then you can put that back together in a path that would be more linked-listy (or whatever is appropriate in your client language) outside the database. You don't have to include parent of course but including it will help you fix up the "pointers".

like image 67
mu is too short Avatar answered Oct 08 '22 01:10

mu is too short