Oracle Where FirstName and LastName in one column in reverse direction - oracle

I have a given database-table where I am not able to change the database-design.
This table contains a column whare names are saved.
The Column "UserName" contains values like "Clinton Bill" or "Trump Donald" or "Bush George".
I need a select statement which is able to find the primary key for the "Bill Clinton" or "Donald Trump"-row.
So the order of Firstname and Lastname is reversed.
Does anybody know how this can be done.
How the Where-Clouse should look like.

If you want to "reverse" such a string (that contains of two words), you can use substr + instr or regular expressions, e.g.
SQL> with test (username) as
2 (select 'Clinton Bill' from dual)
3 select substr(username, instr(username, ' ') + 1) ||' '||
4 substr(username, 1, instr(username, ' ') - 1) as reversed_value,
5 --
6 regexp_substr(username, '\w+', 1, 2) ||' '||
7 regexp_substr(username, '\w+', 1, 1) as reversed_value_2
8 from test;
REVERSED_VALUE REVERSED_VALUE_2
-------------------- --------------------
Bill Clinton Bill Clinton
SQL>
Now, just re-use it (whichever option you want) in another query, e.g.
select id
from test
where regexp_substr(username, '\w+', 1, 2) ||' '||
regexp_substr(username, '\w+', 1, 1) = 'Bill Clinton'

Related

LEFT join query not working in procedure Oracle

I have a query where it generates 18 digit code.
Here is the logic for generating the 18 digit code.
R - Fix
AP – (GIS STATE refer B column from below table)
AP01- (SLP_STATE refer C column from below table)
SMT – (Format refer A Column from below table)
4567 – Store Code
with above logic the code generated is like this R-AN-SOUT--6715
With above 18 digit code, there is 2 error.
1.) For point no second in above logic, where it takes STATE column it only takes the first two digit of the state.
For ex: If the state name is Andhra Pradesh it takes AN but actually it should take AP. Also, if the state name for Mumbai it should take MU where it is taking MU which is correct.
2.) For point number second it is not taking the FORMAT may be due to left join which brings data from another column.
Here is below the query and its description.
SELECT 'R' ||'-'|| UPPER(SUBSTR(r.STATE, 1, 2)) ||'-'|| UPPER(SUBSTR(r.ZONE_NAME, 1, 4))
||'-'|| s.FORMAT_CODE ||'-'|| SUBSTR(r.STORE_CODE, 1,4)
FROM tbl_rrsoc_store_info r
LEFT JOIN tbl_site_store_format s
ON r.STORE_CODE = s.FORMAT_CODE
where r.STORE_CODE = '6715';
Also the table description
Table name:- TBL_RRSOC_STORE_INFO
Name Null Type
--------------------------- -------- --------------
RRSOC_ID NOT NULL NUMBER
STORE_CODE NOT NULL NVARCHAR2(55)
STATE NVARCHAR2(55)
SLP_STATE NVARCHAR2(100)
FORMAT_GROUP NVARCHAR2(100)
Table name:- TBL_SITE_STORE_FORMAT
Name Null Type
------------ ---- -------------
ID VARCHAR2(20)
STORE_FORMAT VARCHAR2(100)
ISACTIVE VARCHAR2(3)
FORMAT_GROUP VARCHAR2(100)
FORMAT_CODE VARCHAR2(50)
You are only selecting the first two characters of the state name. If you want the first letter of the second part of the name, you must code for it.
You are joining tbl_site_store_format on the wrong column, the value from each table should be store_code.
SELECT 'R_'
|| CASE
WHEN INSTR (TRIM (r.state), ' ') > 1
THEN
SUBSTR (r.state, 1, 1)
|| SUBSTR (r.state, INSTR (r.state, ' ') + 1, 1)
ELSE
UPPER (SUBSTR (r.state, 1, 2))
END
|| '-'
|| UPPER (SUBSTR (r.zone_name, 1, 4))
|| '-'
|| s.format_code
|| '-'
|| SUBSTR (r.store_code, 1, 4)
FROM tbl_rrsoc_store_info r
LEFT JOIN tbl_site_store_format s ON r.store_code = s.store_code

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

I have a column "Names" in the "Employee" table that has following values. The values either contain only single name (first, last, username) or Multiple names separated with semicolon (;). I need to search the values from that table either by first name or last name or username.
I have created a procedure but it is fetching only 1st,4th,5th records. Please let me know how to retrieve 2nd and 3rd records as well.
Firstname and lastname can be given by user with minimum of 2 characters length.
Username is given entire.
Employee:
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
Code:
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 ;
Please let me know how to retrieve 2nd and 3rd records as well.
Desired Output:
When searched with firstname = "Andrea", the output is below
ID Name Title
1 Andrea Warbutton (awr01) Manager
When searched with firstname = "Claire", the output is below
ID Name Title
2 Claire Taylor (cta02) HOD
5 Claire Pilkington (cpt09) Sales Owner
When searched with lastname = "Simps", the output is below
ID Name Title
3 Jessica Simpson (jesi10) Analyst
When searched with username = "mak03", the output is below
ID Name Title
2 Mark Kites (mak03) Supervisor
When searched with username = "nik56", the output is below
ID Name Title
4 Nick Ken (nik56) Product (Local,Regional)
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
Your task would be much easier if you normalize these data. Above query outputs:
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
Now you can search first, last, usernames however you want. First expression finds first word, then second and word between brackets.
Edit:
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
This query worked for provided examples:
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
Be careful however, because we cannot write ideal query. If you have entries like Benicio Del Toro, Mary Jo Catlett, Jean Claude Van Damme, it's impossible to write correct regexp. Sometimes second word is part of lastname, sometimes it is firstname, middlename etc.
The proper way is to modify table structure, divide rows, check results and put correct values in correct name columns. Now you have lists which are hard to search and every method may return wrong results.
No need for 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>
What does it do?
temp CTE splits semi-colon separated values into rows
final query uses a simple instr function which detects whether "rows" (extracted previously) contain value you're looking for
If it must be a function, that code can be reused. As you didn't say what exactly (which datatype, I mean) you want to return, I returned a string.
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>

How to convert string value returned from oracle apex 20.1 multiselect item into comma separated numbers array

I have a multi select enabled select list. I want to use all the selected ids inside an IN () operator in pl/sql query. Selected values are returned as below,
"1","5","4"
I want to use em as numbers as below,
1,5,4
My query is like,
UPDATE EMPLOYEE SET EMPSTAT = 'Active' WHERE EMPID IN (:P500_EMPIDS);
This is the employee table:
SQL> select * from employee;
EMPID EMPSTAT
---------- --------
1 Inactive
2 Inactive
4 Inactive
5 Inactive
SQL>
This is a way to split comma-separated values into rows (not into a list of values you'd use in IN!). Note that:
line #3: REPLACE function replaces double quotes with an empty string
line #3: then it is split into rows using REGEXP_SUBSTR with help of hierarchical query
SQL> with test (col) as
2 (select '"1","5","4"' from dual)
3 select regexp_substr(replace(col, '"', ''), '[^,]+', 1, level) val
4 from test
5 connect by level <= regexp_count(col, ',') + 1;
VAL
--------------------
1
5
4
SQL>
Usually multiselect items have colon-separated values, e.g. 1:5:4. If that's really the case, regular expression would look like this:
regexp_substr(col, '[^:]+', 1, level) val
Use it in Apex as:
update employee e set
e.empstat = 'Active'
where e.empid in
(select regexp_substr(replace(:P1_ITEM, '"', ''), '[^,]+', 1, level)
from dual
connect by level <= regexp_count(:P1_ITEM, ',') + 1
);
Result is:
3 rows updated.
SQL> select * from employee order by empid;
EMPID EMPSTAT
---------- --------
1 Active
2 Inactive
4 Active
5 Active
SQL>
Try it.
Thanks for helping everyone.Please check this and tell me if anything is wrong. I found a solution as below,
DECLARE
l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
BEGIN
l_selected := APEX_UTIL.STRING_TO_TABLE(:P500_EMPIDS);
FOR i in 1 .. l_selected.count LOOP
UPDATE EMPLYEE SET EMPSTATUS = 'ACTIVE' WHERE EMPID = to_number(l_selected(i));
END LOOP;
END;
You can use the API apex_string for this. If you want to use the IN operator you'll have to use EXECUTE IMMEDIATE because you cannot use a concatenated string in an IN operator.
Instead what you could do is the following:
DECLARE
l_array apex_t_varchar2;
BEGIN
l_array := apex_string.split(p_str => :P500_EMPIDS, p_sep => ':');
FOR i IN 1..l_array.count LOOP
UPDATE EMPLOYEE SET EMPSTAT = 'Active' WHERE EMPID = l_array(i);
END LOOP;
END;
Explanation: convert the colon separated list of ids to a table of varchar2, then loop through the elements of that table.
Note that I'm using ":" as a separator, that is what apex uses for multi selects. If you need "," then change code above accordingly.
Note that you can use apex_string directly within an update statement, so the answer of Koen Lostrie could be modified to not need a loop:
UPDATE EMPLOYEE
SET EMPSTAT = 'Active'
WHERE EMPID IN (
select to_number(trim('"' from column_value))
from table(apex_string.split(:P500_EMPIDS,','))
);
Testcase:
with cte1 as (
select '"1","2","3"' as x from dual
)
select to_number(trim('"' from column_value))
from table(apex_string.split((select x from cte1),','))

Extracting first_name and last_name from full_name in Oracle

If input is comma separated then store the first part in LAST_NAME and second part in FIRST_NAME.
If comma is not present then store the name in LAST_NAME
Can you please help me in achieving the #2 in oracle?
In my approach am unable to store the full_name in last_name column if there is no comma.
Input :
1. FULL_NAME = "MIKE,MYERS"
2. FULL_NAME = "KFC"
Output :
SELECT SUBSTR('FULL_NAME', 0, INSTR('1,2', ',') - 1) LAST_NAME,
SUBSTR('FULL_NAME', INSTR('1,2', ',', -1) + 1) FIRST_NAME FROM DUAL
**LAST_NAME** **FIRST_NAME**
MIKE MYERS
**LAST_NAME** **FIRST_NAME**
KFC
Since you need two separate columns, I think you would need two CASE statements.
For example,
SQL> WITH DATA AS
2 ( SELECT 'MIKE,MYERS' str FROM dual
3 UNION ALL
4 SELECT 'KFC' str FROM dual
5 )
6 SELECT
7 CASE
8 WHEN instr(str, ',') <> 0
9 THEN SUBSTR(str, 1, INSTR(str, ',', 1) - 1)
10 ELSE str
11 END LAST_NAME,
12 CASE
13 WHEN instr(str, ',') <> 0
14 THEN SUBSTR(str, INSTR(str, ',', 1) +1)
15 ELSE NULL
16 END FIRST_NAME
17 FROM DATA
18 /
LAST_NAME FIRST_NAME
---------- ----------
MIKE MYERS
KFC
SQL>

split string in oracle query

I am trying to fetch phone numbers from my Oracle database table. The phone numbers may be separated with comma or "/". Now I need to split those entries which have a "/" or comma and fetch the first part.
Follow this approach,
with t as (
select 'Test 1' name from dual
union
select 'Test 2, extra 3' from dual
union
select 'Test 3/ extra 3' from dual
union
select ',extra 4' from dual
)
select
name,
regexp_instr(name, '[/,]') pos,
case
when regexp_instr(name, '[/,]') = 0 then name
else substr(name, 1, regexp_instr(name, '[/,]')-1)
end first_part
from
t
order by first_part
;
Lookup substr and instr functions or solve the puzzle using regexp.
I added a table test with one column phone_num. And added rows similar to your description.
select *
from test;
PHONE_NUM
------------------------------
0123456789
0123456789/1234
0123456789,1234
3 rows selected.
select
case
when instr(phone_num, '/') > 0 then substr(phone_num, 0, instr(phone_num, '/')-1)
when instr(phone_num, ',') > 0 then substr(phone_num, 0, instr(phone_num, ',')-1)
else phone_num
end phone_num
from test
PHONE_NUM
------------------------------
0123456789
0123456789
0123456789
3 rows selected.
This generally works. Although it will fail if you have rows with commas and slashes.

Resources