Extract character before space from UK postcode - oracle

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>

Related

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>

select matching string from another table oracle

I have a database (Oracle) Table A with some strings in one of columns, Now I want to get matching records from Table B against each column value of Table A for example,
Table A
Name
-----------
ABC
DEE
GHI
JKL
Table B
Name
-----------
ABC
DEF
GHI
JKL
MNO
PQR
Now i want that each string in Table A must be checked against Table B's column and if some string is found almost identical then it should appear against original Value as per below
Table OutPut
Name Matched
--------|----------
ABC | ABC
DEE | DEF
GHI | GHI
JKL | JKL
I have tried following query
with data as(
SELECT Name FROM TABLE_A UNION ALL
SELECT Name FROM TABLE_B
)
SELECT Name
FROM
(
SELECT t.*,utl_match.edit_distance_similarity(upper(Name),upper('DEE')) eds
FROM data t
ORDER BY eds DESC
)
WHERE rownum = 1
but problem is that using this query i can check only one record at a time and that too against a hard coded string. Is there any way to check whole column from Table A one by one against Table B and produce result in output against each string.
Not too clever (hint: performance issue, but - see if it helps. Might be OK if there aren't too many rows involved.
You need lines 21 onwards.
I set similarity to be greater than 80 - adjust it, if needed (which is very probable, as data you posted is really sample data).
SQL> WITH ta (name)
2 AS (SELECT 'ABC' FROM DUAL
3 UNION ALL
4 SELECT 'DEE' FROM DUAL
5 UNION ALL
6 SELECT 'GHI' FROM DUAL
7 UNION ALL
8 SELECT 'JKL' FROM DUAL),
9 tb (name)
10 AS (SELECT 'ABC' FROM DUAL
11 UNION ALL
12 SELECT 'DEF' FROM DUAL
13 UNION ALL
14 SELECT 'GHI' FROM DUAL
15 UNION ALL
16 SELECT 'JKL' FROM DUAL
17 UNION ALL
18 SELECT 'MNO' FROM DUAL
19 UNION ALL
20 SELECT 'PQR' FROM DUAL)
21 SELECT ta.name,
22 tb.name,
23 UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) sim
24 FROM ta, tb
25 WHERE UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) > 80
26 ;
NAM NAM SIM
--- --- ----------
ABC ABC 100
DEE DEF 82
GHI GHI 100
JKL JKL 100
SQL>

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>

Join same table to display rows as colomn in 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.

how to match an integer with varchar containing digits separated by commas in oracle

I am facing a strange scenario where I need to match an integer with varchar containing digits separated by commas in oracle
Example:
Table t1:
id integer
key integer
Table t2
id integer,
keys varchar2
T1 values are:
1,111
2,201
3,301
T2 values are:
1, "111,301"
2, "111,201"
3, "201,301"
PROBLEM: Is there any way I can match or regular_expression match with key of T1 with keys of T2?
you can do a regular join without regex for this:
select *
from t1
inner join t2
on ','||t2.keys||',' like '%,'||to_char(t1.key)||',%';
eg:
SQL> create table t1(id, key)
2 as
3 select 1, 111 from dual union all
4 select 2, 201 from dual union all
5 select 3, 301 from dual;
Table created.
SQL> create table t2(id, keys)
2 as
3 select 1, '111,301' from dual union all
4 select 2, '111,201' from dual union all
5 select 3, '201,301' from dual;
Table created.
SQL> select *
2 from t1
3 inner join t2
4 on ','||t2.keys||',' like '%,'||to_char(t1.key)||',%';
ID KEY ID KEYS
---------- ---------- ---------- -------
1 111 1 111,301
1 111 2 111,201
2 201 2 111,201
2 201 3 201,301
3 301 1 111,301
3 301 3 201,301
6 rows selected.
It's not regex, just concatenation. For example lets say we wanted to compare
KEY KEYS
111 111,301
we could say
where keys like '%'||key||'%'
i.e. expanded, this is
where '111,301' like '%111%'
which matches fine. But I added some commas there too. ie I did this:
where ',111,301,' like '%,111,%'
Why? imagine instead you had this data:
KEY KEYS
111 1111,301
If we did the simple join:
where '1111,301' like '%111%'
it would incorrectly match. By injecting leading and trailing commas on both sides:
where ',1111,301,' like '%,111,%'
is no longer erroneously matches, as ,1111, isn't like ,111,.

Resources