DuckDB复杂关联

程序员咋不秃头 2024-11-18 04:17:55

现实工作中,有一些场景需要关联,然而却不能直接进行关联,因为关联键并不直接存在,只有经过处理后才可以进行关联,今天,我们通过一个例子来学习一下。

需求背景

假设有通过笔试的候选人名单如下:

pid

name

1

张三

2

李四

3

王五

4

赵六

经过面试、体检及背调等复核工作,发现部分成员存在问题,不能正常入取,示例数据如下:

check_type

names

health

张三、赵六

age

李四

现在要求筛查出符合所有考核要求的候选人名单。

解决思路

要求从通过笔试的候选人名单中,剔除复核过程中不达标的人员。难点在于候选人名单和复核情况名单关键字段结构不一致,候选人的姓名是独立的,而复核表中的姓名是拼接在一起的。

具体到解决思路,有以下几种可以参考:

1、以复核表为基础,把拼接的姓名拆分到行,然后再关联

2、通过正则匹配来关联

3、通过模糊匹配来关联

4、LISTAGG 拼接所有姓名,使用 INSTR 来剔除不达标人员

方法一:拆分到行

首先,将复核表中拼接的姓名拆分到行

select check_type, regexp_split_to_table(cnames, '、') cnamefrom t2;

查询结果:

check_type

cname

health

张三

health

赵六

age

李四

将候选人表与拆分到行的复核表进行关联

select a.cname from t1 aleft join (select check_type, regexp_split_to_table(cnames, '、') cname from t2) bon a.cname = b.cnamewhere b.cname is null;

查询结果:

cname

王五

方法二:正则匹配

首先,将候选人表与复核表进行模糊关联,查找在复核表中出现过的候选人

select t1.cname from t1 join t2 on regexp_matches(t2.cnames,concat(t1.cname, '.*'));

查询结果:

cname

张三

赵六

李四

剔除复核表中出现的候选人

select cnamefrom t1where cname not in ( select t1.cname from t1 join t2 on regexp_matches(t2.cnames,concat(t1.cname, '.*')) );

查询结果:

cname

王五

方法三:模糊匹配

使用模糊匹配 + NOT EXISTS 语法

select cname from t1 a where not exists (select cnames from t2 b where b.cnames like '%'||a.cname||'%');

查询结果:

cname

王五

方法四:listagg + instr

首先使用 listagg 拼接复核表中所有姓名

select listagg(cnames,'、') AS x from t2;

查询结果:

x

张三、赵六、李四

使用 INSTR 剔除在复核表中出现的候选人

with a as (select listagg(cnames,'、') AS x from t2)select cname from t1, awhere instr(a.x, cname) = 0;

查询结果:

cname

王五

至此,四种方法全部介绍完了,你最喜欢哪一种呢?

1 阅读:10