Oracle中连接含非唯一值的表:解决EBS系统活跃用户查询的笛卡尔积及主管姓名展示问题
解决EBS活跃用户查询的笛卡尔积与主管姓名展示问题
咱们先拆解你碰到的两个核心问题,一步步来解决:
一、搞定笛卡尔积问题
你遇到的笛卡尔积,根源很明确:EMPDATA_IMPORT表中同一个email_address对应了多行重复数据(比如示例里jdoe@mm.com出现了3次)。直接用这个表和fnd_user关联时,每一条用户数据都会和所有匹配的重复行关联,结果行数自然就爆炸了。
解决思路是先对EMPDATA_IMPORT做去重处理,保留每个邮箱对应的唯一supervisor_id(从你的数据示例看,同一邮箱的主管ID是一致的,假设业务逻辑也是如此)。我们用CTE(公共表表达式)来生成去重后的数据集,这样SQL可读性会更高。
二、实现主管姓名展示
要通过主管ID拿到对应的姓名,只需要把去重后的员工表自连接一次:用当前用户的supervisor_id关联员工表的emp_id,就能直接获取主管的全名了。
改写后的完整SQL
WITH emp_data_unique AS ( -- 对EMPDATA_IMPORT去重,保留每个邮箱对应的唯一员工/主管数据 SELECT DISTINCT emp_id, full_name, supervisor_id, email_address FROM EMPDATA_IMPORT ) SELECT fu.user_name "User name", frt.responsibility_name "Responsibility Name", furg.start_date "Start Date", furg.end_date "End Date", fu.last_logon_date "Last Logon Date", fr.responsibility_key "Responsibility key", fu.email_address "Email Address", fu.description "Description", x.supervisor_id "Supervisor ID", mgr.full_name "Supervisor Name" -- 新增主管姓名列 FROM fnd_user_resp_groups_direct furg JOIN fnd_user fu ON furg.user_id = fu.user_id JOIN applsys.fnd_responsibility_tl frt ON furg.responsibility_id = frt.responsibility_id JOIN applsys.fnd_responsibility fr ON fr.responsibility_id = frt.responsibility_id JOIN emp_data_unique x ON fu.email_address = x.email_address LEFT JOIN emp_data_unique mgr ON x.supervisor_id = mgr.emp_id -- 自连接获取主管姓名 WHERE (fu.END_DATE IS NULL OR fu.END_DATE > sysdate)
额外注意事项
- 特殊场景处理:如果你的业务中同一邮箱可能对应不同的主管ID(比如存在历史变更记录),可以改用
ROW_NUMBER()函数取最新的记录,示例如下:WITH emp_data_unique AS ( SELECT emp_id, full_name, supervisor_id, email_address, ROW_NUMBER() OVER (PARTITION BY email_address ORDER BY emp_id DESC) rn FROM EMPDATA_IMPORT WHERE rn = 1 -- 取每个邮箱对应的最新记录,排序规则可根据实际调整 ) - 避免数据丢失:用
LEFT JOIN关联主管数据,而不是INNER JOIN,这样即使存在顶级主管(无上级ID),也不会导致该用户的记录被过滤掉。 - 语法优化:把原来的隐式连接改成显式
JOIN语法,SQL结构更清晰,后续排查关联问题也更方便。
内容的提问来源于stack exchange,提问作者user3391373




