下面是代码:
CREATE TABLE audit_trail (
old_email TEXT NOT NULL,
new_email TEXT NOT NULL
);
INSERT INTO audit_trail(old_email, new_email)
VALUES ('harold_gim@yahoo.com', 'hgimenez@hotmail.com'),
('hgimenez@hotmail.com', 'harold.gimenez@gmail.com'),
('harold.gimenez@gmail.com', 'harold@heroku.com'),
('foo@bar.com', 'bar@baz.com'),
('bar@baz.com', 'barbaz@gmail.com');
WITH RECURSIVE all_emails AS (
SELECT old_email, new_email
FROM audit_trail
WHERE old_email = 'harold_gim@yahoo.com'
UNION
SELECT at.old_email, at.new_email
FROM audit_trail at
JOIN all_emails a
ON (at.old_email = a.new_email)
)
SELECT * FROM all_emails;
old_email | new_email
--------------------------+--------------------------
harold_gim@yahoo.com | hgimenez@hotmail.com
hgimenez@hotmail.com | harold.gimenez@gmail.com
harold.gimenez@gmail.com | harold@heroku.com
(3 rows)
select old_email, new_email into iter1
from audit_trail where old_email = 'harold_gim@yahoo.com';
select * from iter1;
-- old_email | new_email
-- ----------------------+----------------------
-- harold_gim@yahoo.com | hgimenez@hotmail.com
-- (1 row)
select a.old_email, a.new_email into iter2
from audit_trail a join iter1 b on (a.old_email = b.new_email);
select * from iter2;
-- old_email | new_email
-- ----------------------+--------------------------
-- hgimenez@hotmail.com | harold.gimenez@gmail.com
-- (1 row)
select * from iter1 union select * from iter2;
-- old_email | new_email
-- ----------------------+--------------------------
-- hgimenez@hotmail.com | harold.gimenez@gmail.com
-- harold_gim@yahoo.com | hgimenez@hotmail.com
-- (2 rows)
正如您所看到的,递归代码以正确的顺序给出结果,而非递归代码则不然。
他们都使用union
,为什么有区别?
3条答案
按热度按时间ua4mk5z41#
基本上,您的查询从一开始就不正确。使用**
UNION ALL
**,而不是UNION
,否则您将错误地删除重复的条目。(并没有说跟踪不能在相同的电子邮件之间来回切换。)而且UNION
很可能会重新排序行。UNION ALL
的Postgres实现通常返回序列中的附加值-只要你 * 不 * 在末尾添加ORDER BY
或对结果做任何其他操作。但是没有正式的保证,并且自从Parallel Append
计划在Postgres 11中出现以来,这实际上可能会中断。但是要注意,除非追加了
ORDER BY
,否则每个SELECT
都将以任意顺序返回行。这通常是可行的:
要获得可靠的排序顺序,并“模拟增长记录”,您可以像这样跟踪级别:
老SQLF
旁白:如果
old_email
没有以某种方式定义为UNIQUE
,那么您可能会得到多个踪迹。您需要一个唯一的列(或列的组合)来保持它的明确性。如果所有其他方法都失败,您可以(ab-)使用内部元组IDctid
来区分踪迹。但是您应该使用自己的列。(在小提琴中添加了示例)考虑:
mepcadol2#
在任何合理的数据库中执行任何操作后都不会保留排序。如果希望结果集具有特定的顺序,请使用
ORDER BY
.period。在
UNION
.UNION
删除重复项之后,这种情况尤其如此,而且该操作很可能会更改行的顺序。vi4fp9gy3#
如果可以按如下方式传递after all unions语句,则保持顺序: