1

I have the following query that I do not understand how it works, especially the subquery that returns the minimum ID without grouping.

WITH RECURSIVE t(id, user_id, name) AS (
  select min(id) - 1, user_id, null as name from attempts group by user_id
UNION ALL
  select * from (
    with t_inner as (select * from t),
    next_id as (
      select min(attempts.id) as id
      from attempts
      left join t_inner using(name)
      where attempts.id > (select min(id) id from t_inner)
      and t_inner.name is null
    )
    select next_id.id, t_inner.user_id, coalesce(attempts.name, t_inner.name) as name
    from t_inner cross join next_id left join attempts
    on (attempts.id = next_id.id)
    and (attempts.user_id = t_inner.user_id)
    where next_id.id is not null
  ) as t2
)
select t.user_id, t.name
from t natural join (select user_id, max(id) as id from t group by user_id) mas_id
order by user_id, id
;

Shouldn't this subquery always return the same number regardless of the iteration step?

(select min(id) id from t_inner)

2 Answers 2

4

t_inner is just an alias for the recursive CTE t. That will be different in different iterations, because, as the documentation describes, we

Evaluate the recursive term, substituting the current contents of the working table for the recursive self-reference.

That is, t is the result of the previous iteration.

0

Since I struggled with this unique feature of PostgreSQL I decided to answer my own question with the hope it will help other confused people to understand how this feature works :-) I my opinion, the manual could have been written better, especially the following part:

a) Evaluate the recursive term, substituting the current contents of the
working table for the recursive self-reference. For UNION (but not UNION ALL),
discard duplicate rows and rows that duplicate any previous result row.
Include all remaining rows in the result of the recursive query, and also
place them in a temporary intermediate table.

The most confusing part for me was substituting the current contents of the working table for the recursive self-reference. It lead me to believe that for every iteration step the entire recursive table is evaluated, which turned out to be not the case. It is only the result from the query specified after UNION (ALL) is participating in the next iteration (including dups elimination from the prior iteration). Again manual is not very clear here which part is evaluated for duplicates in each step - the entire recursive table or just the prior iteration plus the current one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.