Oracle PL/SQL存储过程:如何正确检索含多值的员工姓名匹配记录
解决Oracle Employee表多姓名值的检索存储过程问题
我来帮你搞定这个多姓名匹配的问题!你的核心痛点是原存储过程只会匹配单条姓名的记录,没法处理用分号分隔的多姓名行。咱们先理清楚问题,再给出修正后的方案。
问题梳理
你有一个Employee表,Name列要么是单个姓名(格式:名 姓 (用户名)),要么是多个用分号分隔的这类姓名串。需要实现:
- 按名检索:输入长度至少2字符,匹配姓名开头的名
- 按姓检索:输入长度至少2字符,匹配姓名里的姓
- 按用户名检索:必须输入完整内容,匹配括号里的用户名
现有表数据
| ID | Name | Title |
|---|---|---|
| 1 | Andrea Warbutton (awr01) | Manager |
| 2 | Claire Taylor (cta02);Mark Kites (mak03);Anitha Rooney (anr06) | HOD;Supervisor;Business |
| 3 | Dave Rites (dar12);Jessica Simpson (jesi10) | Lead;Analyst |
| 4 | Nick Ken (nik56) | Product (Local,Regional) |
| 5 | Claire Pilkington (cpt09) | Sales Owner |
原代码的问题
原存储过程不仅语法有错误(比如CREATE OR REPLACE后面缺PROCEDURE、INSTR参数写错、字符串拼接多了空的||),更关键的是它直接对整列Name做匹配,没法拆分多值行里的单个姓名项,所以只能命中单值的记录。原错误代码如下:
-- 原代码存在语法错误,且无法处理多值行 Create or replace empl (pm_firstname varchar2(100), pm_lastname varchar2(100), pm_username varchar2(100)) BEGIN Select * from Employee where Upper(Name) like Upper(pm_firstname ||'%'||) -- 语法错误:多余的|| OR Upper(SUBSTR(Name, INSTR(Name),' '+1)) like Upper(pm_lastname ||'%'||) -- 语法错误:INSTR参数顺序错,多余的|| OR upper(REGEXP_SUBSTR(Name,'\((.+)\)',1,1,NULL,1)) = Upper(pm_username); -- 只提取第一个用户名 END; End empl ;
解决方案:拆分多值行后匹配
核心思路是先用Oracle的CONNECT BY+REGEXP_SUBSTR把多值的Name和Title拆分成单行(保证每个姓名对应其职位),再对拆分后的单个姓名做匹配。
修正后的存储过程
CREATE OR REPLACE PROCEDURE empl( pm_firstname VARCHAR2, pm_lastname VARCHAR2, pm_username VARCHAR2 ) IS BEGIN -- 拆分多值字段为单行,再进行精准匹配 SELECT e.ID, split_name.name_part, split_title.title_part FROM Employee e -- 拆分Name字段为单个姓名行 CROSS JOIN TABLE( CAST( MULTISET( SELECT REGEXP_SUBSTR(e.Name, '[^;]+', 1, LEVEL) FROM DUAL CONNECT BY REGEXP_SUBSTR(e.Name, '[^;]+', 1, LEVEL) IS NOT NULL ) AS SYS.ODCIVARCHAR2LIST ) ) split_name -- 拆分Title字段为对应职位行,和姓名一一对应 CROSS JOIN TABLE( CAST( MULTISET( SELECT REGEXP_SUBSTR(e.Title, '[^;]+', 1, LEVEL) FROM DUAL CONNECT BY REGEXP_SUBSTR(e.Title, '[^;]+', 1, LEVEL) IS NOT NULL ) AS SYS.ODCIVARCHAR2LIST ) ) split_title -- 确保拆分的姓名和职位是同一索引(对应同一人员) WHERE split_name.COLUMN_VALUE = REGEXP_SUBSTR(e.Name, '[^;]+', 1, split_title.COLUMN_VALUE) AND ( -- 名匹配:输入长度≥2,匹配姓名开头的第一个单词 (pm_firstname IS NOT NULL AND LENGTH(pm_firstname) >= 2 AND UPPER(REGEXP_SUBSTR(split_name.name_part, '^\w+')) LIKE UPPER(pm_firstname || '%')) -- 姓匹配:输入长度≥2,匹配姓名里的第二个单词 OR (pm_lastname IS NOT NULL AND LENGTH(pm_lastname) >= 2 AND UPPER(REGEXP_SUBSTR(split_name.name_part, '\w+', 1, 2)) LIKE UPPER(pm_lastname || '%')) -- 用户名匹配:输入完整内容,匹配括号内的字符串 OR (pm_username IS NOT NULL AND UPPER(REGEXP_SUBSTR(split_name.name_part, '\((.+)\)', 1, 1, NULL, 1)) = UPPER(pm_username)) ) ORDER BY e.ID; END empl; /
关键优化说明
- 拆分多值字段:用
CONNECT BY循环拆分分号分隔的内容,把多值行拆成单行记录,让每个姓名单独参与匹配 - 职位关联:同步拆分
Title字段,通过索引关联保证每个姓名对应正确的职位 - 输入校验:添加了名和姓的长度校验(≥2字符),符合你的需求
- 精准匹配:对拆分后的单个姓名提取名、姓、用户名,而非原整列匹配,解决多值行的匹配问题
测试验证(和你的期望完全一致)
搜索firstname = "Andrea"
ID name_part title_part 1 Andrea Warbutton (awr01) Manager 搜索firstname = "Claire"
ID name_part title_part 2 Claire Taylor (cta02) HOD 5 Claire Pilkington (cpt09) Sales Owner 搜索lastname = "Simps"
ID name_part title_part 3 Jessica Simpson (jesi10) Analyst 搜索username = "mak03"
ID name_part title_part 2 Mark Kites (mak03) Supervisor 搜索username = "nik56"
ID name_part title_part 4 Nick Ken (nik56) Product (Local,Regional)
内容的提问来源于stack exchange,提问作者Anitha
相关产品推荐
相关产品推荐

