【发布时间】:2018-05-07 04:39:56
【问题描述】:
我有一个包含 415,000 多行的大表,我需要以非常具体的方式对其进行操作:
这最初是关于人们在网上签署请愿书并将他们的信息保存在 PostgreSQL 数据库中。
-
原来的 'members' 表有一种非常奇怪的方式来处理重复签名者:如果一个人在网站上签署了一份请愿书,它会注册他们的姓名(和其他东西,例如电子邮件地址)并分配他们一个 member_id(主键)。如果此人后来签署了另一份请愿书,但提供了稍微不同的信息,例如他们的姓名拼写错误但使用相同的电子邮件,则数据库将创建一个新成员并使用新的 member_id
最终,手动合并脚本会将两个成员之一标记为 state='deleted' 并为其分配一个 'successor_id' - 保持为 state='active' 的另一个成员的 member_id
问题是:数据库中的其他表,例如特定请愿书的签名者列表,仍然引用旧记录的 member_id,现在已删除。通常,这可以通过简单地加入成员表并使用successor_id 字段来解决,但是......更糟糕的是,一些成员已经合并了3、4 甚至5 次。本质上意味着被删除的成员可以有一个successor_id,它有一个successor_id,它有一个successor_id……等等。
现在我需要将所有已签署特定请愿书的 member_id 导出到 .csv,并且我需要将所有这些已删除的成员解析为他们当前的实际 member_id,无论它是 1 个还是 5 个合并的成员。
实现这一目标的最佳方法是什么?要创建名为 'successor_id_2'、'successor_id_3' 等的新列,然后只使用非空白的最远的successor_id 字段?还是有其他一些聪明的方法来生成特定成员的所有后续successor_id 的列表?我真的很茫然。
更新:我尝试使用递归查询来获取一列规范 id(即一个活跃成员的id),这样做:
WITH RECURSIVE canonicalCTE AS (
SELECT
id,
name,
successor_id, canonical_id
FROM
members
UNION ALL
SELECT
members.id,
members.name,
members.successor_id,
members.canonical_id
FROM
members
JOIN canonicalCTE ON members.id = canonicalCTE.successor_id
)
UPDATE members
SET canonical_id = m1.id
FROM canonicalCTE m0
LEFT JOIN canonicalCTE m1
ON m0.successor_id = m1.id;
但是除了由于缺乏资源而使我的计算机完全崩溃之外,我不确定这是找到它的正确方法吗? (它仍在运行)
【问题讨论】:
-
你拥有的是本质上一个链表。你可能想要的是:为每个真实的人分配一个唯一的canonical id。对此的自然选择是该人发生的最低值。您最终会得到一个表 {canonical_it, this_id} 将当前 id 映射到第一个。这可以通过将 canon_id 添加到原始表中来完成,或者将其放入单独的映射表中。要填充它,您要么必须迭代几次,要么使用递归查询来获取每个人的第一条记录。
-
我不确定你想要达到什么目的。您能否请edit 提出您的问题并为
members表和一些sample data 添加create table语句以及基于该示例数据的预期输出。
标签: sql database postgresql