postgresql 用于交叉检查2个表的Postgres查询

9ceoxa92  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(123)

我有两个表,已经填充了数据,如下所示:
table1数据是公民数据,具有以下字段:

uniqid  (a uniqueIP for person, like social sec num) 
first_name 
last_name
birthdate
address

字符串
table2带字段:

first_name 
last_name
birthdate
address
gender
healthinsurance_type
...


table1数据和table2数据来自不同的独立机构。这些表中的名称可以以不同的方式键入,等等。
table1对名称和ID具有权威性。table2是我需要处理的,但是没有ID(citizenID)。
现在,我需要table2中的每一行来获取一个citizenid,它与table1相关联,这样最后我就得到了带有附加ID列的table2,它与每个人都正确关联。
比如在table1中搜索某个条件匹配的人(table2中的一行),如果table1中存在一条记录,则将该记录的ID放入table2中的一列。
但要快,而且要排好。
表1的行计数大约为200万。
表2的行数大约为900.000

gmxoilav

gmxoilav1#

我假设您是唯一一个向这些表写入数据的人,因此没有并发冲突。

第一步

将ID列添加到table2,现在可以为NULL:

ALTER TABLE table2 ADD COLUMN citizenid int; -- or whatever the type is

字符串
考虑在table1上添加一个标记,以便在另一边廉价地将row“撤出市场”:

ALTER TABLE table1 ADD COLUMN hasmatch boolean;

第二步

假设两边都没有复制品。否则你需要做更多。

第三步

使用完美、完全匹配更新表2中的所有行。也可以立即标记table1中的匹配行。使用数据修改CTE

WITH u2 AS (
   UPDATE table2 t2
   SET    citizenid = t1.uniqid  
   FROM   table1 t1
   WHERE  t1.hasmatch IS NULL   -- always with this condition
   AND    t2.citizenid IS NULL  -- always with this condition
   AND    t2.first_name = t1.first_name
   AND    t2.last_name  = t1.last_name
   AND    t2.birthdate  = t1.birthdate
   AND    t2.address    = t1.address
   RETURNING citizenid
   )
UPDATE table1 t1
SET    hasmatch = TRUE
FROM   u2
WHERE  t2.citizenid = u2.citizenid;


只要一行有了citizenid,它就在两边都“退出市场”了。

第四步

检查还剩多少行,并开始**逐步软化 predicate **,始终首先尝试更可能的匹配,以防止误报。在你开始这个循环过程之前,想一个系统的策略。分析剩余的行,找出系统性的错别字或类似的线索。
字符类型列的模糊匹配的可能选项包括:

lower(t2.address) = lower(t1.address)
t2.address ILIKE (t1.address || %) -- here % is a wilcard for LIKE pattern
t1.address ILIKE (t2.address || %)
lower(left(t2.address, 20)) = lower(left(t1.address, 20))
t2.address % t1.address  -- here % is the similarity operator
levenshtein(t2.address, t1.address) <= 3  -- *very* expensive, no index support


相似性运算符%由附加模块pg_trgm提供,该模块还提供三元组索引以支持LIKE和相似性匹配。您将 * 需要 * 索引**进行模糊匹配,否则您的查询可能需要 * 长 * 时间。

  • PostgreSQL LIKE查询性能变化

考虑使用部分索引,以便在找到匹配项后立即从索引中删除行。喜欢的:

CREATE INDEX t1_adr_gin_trgm_idx ON table1 USING gin (address gin_trgm_ops)
WHERE t1.hasmatch IS NULL;

CREATE INDEX t2_adr_gin_trgm_idx ON table2 USING gin (address gin_trgm_ops)
WHERE t2.citizenid IS NULL;


等等。
您可以使用以下命令微调%运算符的相似性阈值:

SELECT set_limit(0.8);

第五步

有一小部分仍将悬而未决。您可以花费越来越多的时间来手动分配它们,直到您决定放弃其余的。

第六步

可选。当过程完成时,每行都有一个citizenid,现在可以设置为NOT NULL,新行必须有一个citizenid
更多详情:

相关问题