Join same table to display rows as colomn in oracle - oracle

I have a scenario where I need to take few rows from column and make it as separate column.
My present table:
Id Description
1 abc
2 abc
3 abc
4 abc
1 xyz
2 xyz
3 xyz
4 xyz
Required output:
id Desp1 Desp2
1 abc xyz
2 abc xyz
3 abc xyz
4 abc xyz
Can any one help me with this.

You could make use of the listagg function and a combination of instr and substr functions, instead of a self Join.
select id,substr(Description, 0, instr(Description, ',',1,1)-1) Desp1,
substr(Description, instr(Description, ',',1,1)+1) Desp2
from
(select id, listagg(Description,',') within group (order by Description) as
Description from sam group by id)
Note: The above query delimits the Description field by comma, and splits only into two columns as depicted in your example.

Related

Extract character before space from UK postcode

In my data Postcode records are as below
1.'ABC XYZ'
2.' EFG PQR'
Requirements is to get all character before space
So for first record ,I am getting expected result if I am putting
select NVL(substr(postcode,0,instr(postcode,' ')-1), postcode)
But for second record I am getting whole postcode value . Because in second record ' '(space is at very beginning).
I tried multiple query but not getting the results .
I want single expression which handles both scenarios.
Try this:
NVL(substr(ltrim(postcode),0,instr(ltrim(postcode),' ')-1), postcode)
A simple option uses regular expressions:
Sample data:
SQL> with test (id, postcode) as
2 (select 1, 'ABC XYZ' from dual union all
3 select 2, ' EFG PQR' from dual
4 )
Query:
5 select id, postcode,
6 regexp_substr(postcode, '\w+') result
7 from test;
ID POSTCODE RESULT
---------- -------- --------
1 ABC XYZ ABC
2 EFG PQR EFG
SQL>

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>

ORACLE : How to use manual ID generated using MAX ID with Oracle Merge statement insert query

I have 2 tables like below,
Master_Data_1
Id Name
1 AAA
2 BBB
3 DDD
4 CCC
Master_Data_2
Id Name Upt_Flg
1 DDD False
2 EEE False
3 FFF False
both tables have same ID but different Name, and ID field is neither auto incremented nor sequence. But ID is a not null primary key column which will be generated based on MAX ID logic.
In this case i am trying to merge Master_Data_1 table with Master_Data_2 table using oracle merge statement.
So i am having issue in WHEN NOT MATCHED THEN case, i am trying to insert not matched records in to Master_data_2 table from master_data_1 table.
In this scenario ID in Master_Data_2 table will not be auto incremented, and also i cannot use the source table ID here because it will lead to unique constraint exception.
Note : I don't want to alter a table to make ID auto increment or adding sequence for ID.
Expected Output in Master_Data_2 table using merge query:
Id Name Upt_Flg
1 DDD TRUE
2 EEE False
3 FFF False
4 AAA False
5 BBB False
6 CCC False
is there any other way to achieve this?
I guess ROW_NUMBER analytic function might help you here.
MERGE INTO Master_Data_2 md2
USING (SELECT (SELECT MAX(id) FROM Master_Data_2) + ROW_NUMBER() OVER(ORDER BY id) new_id
,name
FROM Master_Data_1
) md1
ON (md2.name = md1.name)
WHEN MATCHED THEN UPDATE
SET Upt_flg = 'TRUE'
WHEN NOT MATCHED THEN
INSERT (md2.id, md2.name)
VALUES (Md1.new_id, md1.name);
Here is the fiddle
You can simply achieve it using INSERT and MINUS operator as following:
insert into master_data_2
select
(select max(id) from master_data_2) + row_number() over (order by 1),
name
from
(select name from master_data_1
minus
select name from master_data_2)
db<>fiddle demo
Cheers!!

PLSql stored procedure to convert data of column in select statement

I want to create a pl/sql procedure in which I want to retrieve the value of column from a table based on another column and I want the output as select query having the field values of the column as the column name.
Suppose I have a table having two columns as
test1:
column 1 column 2
-----------------
abc 123
abc 234
abc 453
abab 4546
abab 454665
abab 4564566
I want the result as select 123, 234, 453 from abc when I provide the input variable for column 1
You can use the below query in procedure to retreive the result:
select listagg(column2, ',') within group (order by column1) from test1
where column1 = 'abc';

Concatenation of query

How do i concatenate
SELECT abc,
abcd
FROM table
WHERE abc IN (SELECT efg
FROM table2
WHERE gfh LIKE'%a%')
in single quotes. I am having a problem while concatenating ',% and ) at the end of this query.
The best way is to use the quoting string literal technique. The syntax is q'[...]', where the "[" and "]" characters can be any of the following as long as they do not already appear in the string.
!
[ ]
{ }
( )
< >
Test case
SQL> SELECT
2 q'[select abc, abcd
3 from table
4 where abc in
5 (select efg
6 from table2
7 where gfh like '%a%')]' str_concat
8 FROM dual
9 /
STR_CONCAT
-----------------------------------------------
select abc, abcd
from table
where abc in
(select efg
from table2
where gfh like '%a%')
SQL>

Resources