如何在oracle plsql中的存储过程中过滤和检索特定字符后的结果?

How to filter and retrieve the results after a Specific characters from stored procedure in oracle plsql?

我在“员工”table 中有一列“姓名”,它具有以下值。这些值要么仅包含单个名称(名字、姓氏、用户名),要么包含多个名称,并以分号 (;) 分隔。我需要通过名字、姓氏或用户名从 table 中搜索值。

我创建了一个过程,但它只获取第 1、4、5 条记录。请让我知道如何检索第二条和第三条记录。

名字和姓氏可以由用户给出,长度至少为 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 empl (pm_firstname varchar2(100), 
                        pm_lastname varchar2(100),
                        pm_username varchar2(100))

BEGIN

Select * from Employee
where Upper(Name) like Upper(pm_firstname ||'%'||) -- this will fetch 1st,4th,5th record
OR Upper(SUBSTR(Name, INSTR(Name),' '+1)) like Upper(pm_lastname ||'%'||) -- this will fetch 1st,4th,5th  record
OR upper(REGEXP_SUBSTR(Name,'\((.+)\)',1,1,NULL,1)) = Upper(pm_username); -- -- this will fetch 1st,4th,5th record

END;

End empl ;

请告诉我如何检索第 2 条和第 3 条记录。

期望输出:

当使用 firstname = "Andrea" 搜索时,输出如下

ID     Name                                  Title
1      Andrea Warbutton (awr01)              Manager

当使用 firstname = "Claire" 搜索时,输出如下

ID      Name                                Title
2      Claire Taylor (cta02)                HOD
5      Claire Pilkington (cpt09)            Sales Owner

当搜索 lastname = "Simps" 时,输出如下

ID     Name                                 Title
3      Jessica Simpson (jesi10)             Analyst

使用用户名 = "mak03" 搜索时,输出如下

ID     Name                                Title
2      Mark Kites (mak03)                 Supervisor

使用用户名 = "nik56" 搜索时,输出如下

ID     Name                                Title
4      Nick Ken (nik56)                   Product (Local,Regional)

不需要PL/SQL。

SQL> with temp as
  2    (select id,
  3      regexp_substr(name, '[^;]+', 1, column_value) name
  4     from employee cross join
  5       table(cast(multiset(select level from dual
  6                           connect by level <= regexp_count(name, ';') + 1
  7                          ) as sys.odcinumberlist))
  8    )
  9  select id, name
 10  from temp
 11  where instr(name, '&search_for_name') > 0;
Enter value for search_for_name: Claire

        ID NAME
---------- ------------------------------
         2 Claire Taylor (cta02)
         5 Claire Pilkington (cpt09)

SQL> /
Enter value for search_for_name: mak03

        ID NAME
---------- ------------------------------
         2 Mark Kites (mak03)

SQL>

它有什么作用?

  • temp CTE 将分号分隔的值拆分成行
  • 最终查询使用一个简单的 instr 函数来检测“行”(之前提取的)是否包含您要查找的值

如果它必须是一个函数,则可以重用该代码。由于您没有说出您想要 return 的确切内容(我的意思是哪种数据类型),我 return 编辑了一个字符串。

SQL> create or replace function f_search (par_what in varchar2)
  2    return sys.odcivarchar2list
  3  is
  4    retval sys.odcivarchar2list;
  5  begin
  6    with temp as
  7    (select id,
  8      regexp_substr(name, '[^;]+', 1, column_value) name
  9     from employee cross join
 10       table(cast(multiset(select level from dual
 11                           connect by level <= regexp_count(name, ';') + 1
 12                          ) as sys.odcinumberlist))
 13    )
 14    select id ||' - '|| name
 15    bulk collect into retval
 16    from temp
 17    where instr(name, par_what) > 0;
 18
 19    return retval;
 20  end;
 21  /

Function created.

SQL> select * from table(f_search('Andrea'));

COLUMN_VALUE
--------------------------------------------------------------------------------
1 - Andrea Warbutton (awr01)

SQL> select * from table(f_search('Claire'));

COLUMN_VALUE
--------------------------------------------------------------------------------
2 - Claire Taylor (cta02)
5 - Claire Pilkington (cpt09)

SQL>
with 
  x as (select id, name, '"'||replace(name, ';', '","')||'"' xml from employee),
  n as (select id, name, column_value as cv from x, xmltable(xml))
select id, 
       trim(regexp_substr(cv, '(\S*)(\s)')) fname,
       trim(regexp_substr(cv, '(\S*)(\s)', 1, 2)) lname,
       regexp_substr(cv, '\((.+)\)', 1, 1, NULL, 1) uname
  from n

如果将这些数据标准化,您的任务会容易得多。以上查询输出:

ID FNAME    LNAME       UNAME
1  Andrea   Warbutton   awr01
2  Claire   Taylor      cta02
2  Mark     Kites       mak03
2  Anitha   Rooney      anr06
3  Dave     Rites       dar12
3  Jessica  Simpson     jesi10
4  Nick     Ken         nik56
5  Claire   Pilkington  cpt09

demo

现在您可以根据需要搜索第一个、最后一个用户名。第一个表达式找到第一个词,然后是第二个和 .


编辑:

I posted the table structure with just ID and Name columns. However, I have Titles column also in the same format separated with (semicolon). In this case, How can I Normalize Titles as well along with Names

此查询适用于提供的示例:

with 
  x as (select id, name, '"'||replace(name, ';', '","')||'"' xmln,
               '"'||replace(title, ';', '","')||'"' xmlt 
          from employee),
  n1 as (select id, trim(xn.column_value) nm, rownum rn from x, xmltable(xmln) xn),
  n2 as (select id, trim(xt.column_value) tt, rownum rn from x, xmltable(xmlt) xt)
select id, trim(regexp_substr(nm, '(\S*)(\s)')) fname,
       trim(regexp_substr(nm, '(\S*)(\s)', 1, 2)) lname,
       regexp_substr(nm, '\((.+)\)', 1, 1, NULL, 1) uname,
       tt title
  from n1 join n2 using (id, rn)

dbfiddle demo

但是要小心,因为我们无法编写理想的查询。如果您有像 Benicio Del Toro、Mary Jo Catlett、Jean Claude Van Damme 这样的条目,则不可能编写正确的正则表达式。有时第二个词是姓氏的一部分,有时是名字、中间名等。 正确的方法是修改 table 结构,划分行,检查结果并将正确的值放入正确的名称列中。现在您有难以搜索的列表,并且每种方法都可能 return 错误的结果。