我有以下测试表:
SELECT * FROM attempts order by id;
id | user_id | name
----+---------+------
1 | 1 | a
2 | 2 | b
3 | 1 | b
4 | 1 | c
5 | 2 | a
6 | 1 | a
7 | 1 | b
8 | 1 | a
9 | 3 | c
10 | 4 | d
11 | 3 | d
(11 rows)我正在尝试调试下面的递归查询,因此我在结果集中打印出每个迭代id。
WITH RECURSIVE t(iter_id, id, user_id, name, aname, iname) AS (
select 1, min(id) - 1, user_id, null, null, null as name from attempts group by user_id
UNION ALL
select * from (
with iter as (select * from t),
t_min as (select min(id) as id from iter),
next_id as (
select min(attempts.id) as id
from attempts
left join iter using(name)
where attempts.id > (select id from t_min)
and iter.name is null
)
select iter.iter_id + 1, next_id.id, iter.user_id, coalesce(attempts.name, iter.name) as name, attempts.name aname, iter.name as iname
from iter cross join next_id left join attempts
on (attempts.id = next_id.id)
and (attempts.user_id = iter.user_id)
where next_id.id is not null
) as t2
)
select *
from t
order by iter_id, user_id, id
;
iter_id | id | user_id | name | aname | iname
---------+----+---------+------+-------+-------
1 | 0 | 1 | NULL | NULL | NULL
1 | 1 | 2 | NULL | NULL | NULL
1 | 8 | 3 | NULL | NULL | NULL
1 | 9 | 4 | NULL | NULL | NULL
2 | 1 | 1 | a | a | NULL
2 | 1 | 2 | NULL | NULL | NULL
2 | 1 | 3 | NULL | NULL | NULL
2 | 1 | 4 | NULL | NULL | NULL
3 | 2 | 1 | a | NULL | a
3 | 2 | 2 | b | b | NULL
3 | 2 | 3 | NULL | NULL | NULL
3 | 2 | 4 | NULL | NULL | NULL
4 | 4 | 1 | c | c | a
4 | 4 | 2 | b | NULL | b
4 | 4 | 3 | NULL | NULL | NULL
4 | 4 | 4 | NULL | NULL | NULL
5 | 5 | 1 | c | NULL | c
5 | 5 | 2 | a | a | b
5 | 5 | 3 | NULL | NULL | NULL
5 | 5 | 4 | NULL | NULL | NULL
6 | 7 | 1 | b | b | c
6 | 7 | 2 | a | NULL | a
6 | 7 | 3 | NULL | NULL | NULL
6 | 7 | 4 | NULL | NULL | NULL
7 | 9 | 1 | b | NULL | b
7 | 9 | 2 | a | NULL | a
7 | 9 | 3 | c | c | NULL
7 | 9 | 4 | NULL | NULL | NULL
8 | 10 | 1 | b | NULL | b
8 | 10 | 2 | a | NULL | a
8 | 10 | 3 | c | NULL | c
8 | 10 | 4 | d | d | NULL
(32 rows)我不明白为什么在迭代编号6上,下一个尝试id变成7而不是6。为了调试这个步骤,我创建了一个临时表,其值表示递归步骤5:
select * from tmp;
id | user_id | name
----+---------+------
5 | 1 | c
5 | 2 | b
5 | 3 | NULL
5 | 4 | NULL
(4 rows)当我对tmp表运行相同的查询时,我得到了预期的结果。
with iter as (select * from tmp),
t_min as (select min(id) as id from iter),
next_id as (
select min(attempts.id) as id
from attempts
left join iter using(name)
where attempts.id > (select id from t_min)
and iter.name is null
)
select next_id.id, iter.user_id, coalesce(attempts.name, iter.name) as name, attempts.name aname, iter.name as iname
from iter cross join next_id left join attempts
on (attempts.id = next_id.id)
and (attempts.user_id = iter.user_id)
where next_id.id is not null
;
id | user_id | name | aname | iname
----+---------+------+-------+-------
6 | 1 | a | a | c
6 | 2 | b | NULL | b
6 | 3 | NULL | NULL | NULL
6 | 4 | NULL | NULL | NULL
(4 rows)为甚麽会有这样的差异呢?这是PostgreSQL中的一个可能的bug吗?
发布于 2023-03-08 12:53:41
您将使用JOINing attempts和iter (name)。Name是您的3个文本列中的第一个列,在迭代5中它包含了c和a,而不是c和b,它们位于您命名为iname的最后一列上。
https://dba.stackexchange.com/questions/324510
复制相似问题