现实工作中,有一些场景需要关联,然而却不能直接进行关联,因为关联键并不直接存在,只有经过处理后才可以进行关联,今天,我们通过一个例子来学习一下。
假设有通过笔试的候选人名单如下:
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, '、') cname
from t2;
查询结果:
check_type | cname |
---|---|
health | 张三 |
health | 赵六 |
age | 李四 |
将候选人表与拆分到行的复核表进行关联
select a.cname
from t1 a
left join (select check_type, regexp_split_to_table(cnames, '、') cname
from t2) b
on a.cname = b.cname
where b.cname is null;
查询结果:
cname |
---|
王五 |
首先,将候选人表与复核表进行模糊关联,查找在复核表中出现过的候选人
select t1.cname
from t1
join t2
on regexp_matches(t2.cnames,concat(t1.cname, '.*'));
查询结果:
cname |
---|
张三 |
赵六 |
李四 |
剔除复核表中出现的候选人
select cname
from t1
where 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 拼接复核表中所有姓名
select listagg(cnames,'、') AS x from t2;
查询结果:
x |
---|
张三、赵六、李四 |
使用 INSTR 剔除在复核表中出现的候选人
with a as (select listagg(cnames,'、') AS x from t2)
select cname
from t1, a
where instr(a.x, cname) = 0;
查询结果:
cname |
---|
王五 |