Separate house number and addition in oracle SQL - sql

I have a problem with my Oracle SQL string and don't get the correct result.
I have a table with Housenumber and addition in one field, i.e. 16f
As result I want it in 2 Fields:
Housenumber Addition
16 f
Housenumber is a Number (1 or more digits)
Addition is a Letter
I have the same Problem with the Fields Ortsname and Ortszusatz there it works. But I can't get it with the Housenumber. the result is a duplication of my entries.
WITH TEST_DATA AS
(SELECT distinct '*' Ort, Nummer FROM adresses)
SELECT
Houseid,
Streetid,
Gemeindeschl,
Gemeinde,
Bundesland,
Landkreis,
REGEXP_SUBSTR(t.Ort, '[^,]+', 1, 1) Ort,
REGEXP_SUBSTR(t.Ort, '[^,]+', 1, 2) Ortszusatz,
Strasse,
regexp_substr(t.Nummer, '[^0-9,]',1, 1) Housenumber,
regexp_substr(t.Nummer, '[^A-Z,]',1, 2) Addition,
Objektkl,
Lng,
Lat,
Plz
FROM adresses T

As you said - fetch "digits" and "letters" separately:
SQL> with addresses (houseid, housenumber) as
2 (select 1, '16f' from dual union all
3 select 2, '20' from dual
4 )
5 select houseid,
6 regexp_substr(housenumber, '[[:digit:]]+') housenumber,
7 regexp_substr(housenumber, '[[:alpha:]]+') addition
8 from addresses;
HOUSEID HOUSENUMBER ADDITION
---------- --------------- ---------------
1 16 f
2 20
SQL>

Related

Using regexp_like in Oracle to match on multiple string conditions

I have a column called Keywords in my Oracle database, Basically Keywords column contains all the data of other columns in particular row separated by _.
Example Table:
NAME PHONE_NUMBER COMPANY ADDRESS ZIPCODE KEYWORD
ABCD 9849523459 MICRO RAJAHMU 532819 ABCD_9849523459_MICRO_RAJAHMU_532819
ABCD 8628738646 INFOS KAKINAD 532775 ABCD_8628738646_INFOS_KAKINAD_532775
ABCD 8473874381 ICUBE RAVULAP 537238 ABCD_8473874381_ICUBE_RAVULAP_537238
Now, How can i get exact string match by using REGEXP_LIKE. When i'm using the below query
SELECT * FROM USER_DATA WHERE 1=1 AND REGEXP_LIKE ('KEYWORD', 'ABCD_MICRO_RAVULAP', 'i'));
It's returning 0 records
My expected output should be
NAME PHONE_NUMBER COMPANY ADDRESS ZIPCODE KEYWORD
ABCD 9849523459 MICRO RAJAHMU 532819 ABCD_9849523459_MICRO_RAJAHMU_532819
ABCD 8473874381 ICUBE RAVULAP 537238 ABCD_8473874381_ICUBE_RAVULAP_537238
I would be very grateful if anyone help me out.
Thanks Inadvance
Something like this?
SQL> with user_data (name, keyword) as
2 (select 'ABCD', 'ABCD_9849523459_MICRO_RAJAHMU_532819' from dual union all
3 select 'DEFG', 'ABCD_8628738646_INFOS_KAKINAD_532775' from dual union all
4 select 'HIJK', 'ABCD_8473874381_ICUBE_RAVULAP_537238' from dual
5 )
6 select *
7 from user_data
8 where regexp_like(keyword, 'ABCD.+MICRO', 'i');
NAME KEYWORD
---- ------------------------------------
ABCD ABCD_9849523459_MICRO_RAJAHMU_532819
SQL>
If you want to search the string for two words in any order, use | operator:
SQL> with user_data (name, keyword) as
2 (select 'ABCD', 'ABCD_9849523459_MICRO_RAJAHMU_532819' from dual union all
3 select 'DEFG', 'ABCD_8628738646_INFOS_KAKINAD_532775' from dual union all
4 select 'HIJK', 'ABCD_8473874381_ICUBE_RAVULAP_537238' from dual union all
5 select 'LMNO', 'MICRO_241241242_ABCD_WHATEVER_241424' from dual
6 )
7 select *
8 from user_data
9 where regexp_like(keyword, '(ABCD).+(MICRO)|(MICRO).+(ABCD)', 'i');
NAME KEYWORD
---- ------------------------------------
ABCD ABCD_9849523459_MICRO_RAJAHMU_532819
LMNO MICRO_241241242_ABCD_WHATEVER_241424
SQL>
However, it isn't practical. Perhaps you should consider Oracle Text feature, then.
SQL> create table
2 user_data (name, keyword) as
3 (select 'ABCD', 'ABCD_9849523459_MICRO_RAJAHMU_532819' from dual union all
4 select 'DEFG', 'ABCD_8628738646_INFOS_KAKINAD_532775' from dual union all
5 select 'HIJK', 'ABCD_8473874381_ICUBE_RAVULAP_537238' from dual union all
6 select 'LMNO', 'MICRO_241241242_ABCD_WHATEVER_241424' from dual
7 );
Table created.
SQL> create index i1_ud on user_data(keyword) indextype is ctxsys.context;
Index created.
SQL> select *
2 from user_data
3 where contains (keyword, '$micro and abcd', 1) > 0;
NAME KEYWORD
---- ------------------------------------
ABCD ABCD_9849523459_MICRO_RAJAHMU_532819
LMNO MICRO_241241242_ABCD_WHATEVER_241424
SQL>
Use IN on the underlying columns rather than trying to parse the composite column:
SELECT *
FROM USER_DATA
WHERE (name, company, address) IN (
('ABCD', 'MICRO', 'RAVULAP'),
('MICRO', 'ABCD', 'RAVULAP')
);
If you want to compare case-insensitively then use UPPER:
SELECT *
FROM USER_DATA
WHERE (UPPER(name), UPPER(company), UPPER(address)) IN (
('ABCD', 'MICRO', 'RAVULAP'),
('MICRO', 'ABCD', 'RAVULAP')
);
If you want to match a single triplet of values to the terms in any order then you can reverse the IN clause:
SELECT *
FROM USER_DATA
WHERE ('ABCD', 'MICRO', 'RAVULAP') IN (
(UPPER(name), UPPER(company), UPPER(address)),
(UPPER(name), UPPER(address), UPPER(company)),
(UPPER(company), UPPER(name), UPPER(address)),
(UPPER(company), UPPER(address), UPPER(name)),
(UPPER(address), UPPER(name), UPPER(company)),
(UPPER(address), UPPER(company), UPPER(name))
);

Oracle SQL - break 1 row into 2 rows

I have the following table:
create table members
(
member_number number(10),
title varchar2(5),
lastname varchar2(30),
personal_email varchar2(20),
work_email varchar2(20)
)
with the data
Insert into MEMBERS
(MEMBER_NUMBER, TITLE, LASTNAME, PERSONAL_EMAIL, WORK_EMAIL)
Values
(11, 'MR', 'Dore', 'personal#email.com', 'work#email.com');
COMMIT;
select member_number, title, lastname,
decode (:pi_email,
'Work', work_email, personal_email) destination
from members
where member_number = 11
and decode (:pi_email,
'Work', work_email, personal_email) is not null
union
select member_number, title, lastname, work_email
from members
where member_number = 11
and :pi_email = 'Both'
and work_email is not null
Question:
Is it possible to re-write the code using 1 select and not using a UNION.
I want to be able to pass pi_email value of 'Work' and select the work_email, alternatively select the personal_email, however if I pass 'Both' I want to select both email addresses in 2 lines/rows.
If I understand correctly, you can unpivot the data and then use a where clause. In Oracle 12C+, you can do this using a lateral join:
select m.member_number, m.title, m.lastname, e.email
from members m cross join lateral
(select 'work' as which, m.work_email as email from dual union all
select 'personal' as which, m.personal_email from dual
) e
where :pi_email in (e.which, 'both');
In earlier versions of Oracle, you can do something similar with union all in the from clause.
How about a CTE with additional column (what in my example, which tells what kind of an e-mail address is that)?
Sample data:
SQL> select * from members;
MEMBER_NUMBER TITLE LASTNAME PERSONAL_EMAIL WORK_EMAIL
------------- ----- ---------- -------------------- --------------------
11 MR Dore personal#email.com work#email.com
Query (runs in SQL*Plus) - fetch work e-mail address:
SQL> set ver off
SQL> with data as
2 (select 'P' what, member_number, title, lastname, personal_email email
3 from members
4 union all
5 select 'W' what, member_number, title, lastname, work_email email
6 from members
7 )
8 select member_number,
9 title,
10 lastname,
11 email
12 from data
13 where member_number = &pi_memnum
14 and (what = '&&pi_email' or '&&pi_email' is null);
Enter value for pi_memnum: 11
Enter value for pi_email: W
MEMBER_NUMBER TITLE LASTNAME EMAIL
------------- ----- ---------- --------------------
11 MR Dore work#email.com
Another example, which fetches both e-mail addresses (what is left NULL):
SQL> undefine pi_email
SQL>
SQL> /
Enter value for pi_memnum: 11
Enter value for pi_email:
MEMBER_NUMBER TITLE LASTNAME EMAIL
------------- ----- ---------- --------------------
11 MR Dore personal#email.com
11 MR Dore work#email.com
SQL>
If you don't use SQL*Plus, the last two lines (i.e. the where clause) would be
where member_number = :pi_memnum
and (what = :pi_email or :pi_email is null);

i am using oracle apex shuttle control. Here is, time list i want some kind of data from given shuttle image i am sharing

i have four columns named as start_time,end_time,class_time and class_duration
and insert whole record in a single row like
start_time should be 0900AM
, end_time should be 1000AM
, class_time should be 0930AM:0930AM
and class_duration should be 60 that is 60 minutes
Shuttle item, as any select list item, uses list of values whose select statement has to contain exactly two columns:
display value
return value
Display value is what users see, return value is what you store into the database, usually some kind of an ID.
If you want to display all those 4 values, you'll have to concatenate them, such as
select 'Start time: ' || start_time ||
'End time: ' || end_time ||
'Class time: ' || class_time ||
'Duration: ' || duration as display_value,
--
something as return_value
from your_table
If there's nothing "special" to return (i.e. no ID), you can use the same concatenated columns for both display and return values.
[EDIT: how to insert data into a table?]
Suppose this is the target table:
SQL> create table schedule
2 (id number,
3 cstart varchar2(6),
4 cend varchar2(6),
5 cclass varchar2(6),
6 duration varchar2(6));
Table created.
Then suppose that values shuttle item contains looks like this:
Start=0900AM,End=1000AM,Class=1030AM,Duration=60
Values are separated by commas (because, if you select multiple values in a shuttle item, they will be separated by colons so - you'd rather pick something else for your separator).
Those multiple values look like this: 1:2:4:8 represents 4 shuttle values.
Now, insert: see comments within code:
SQL> insert into schedule (id, cstart, cend, cclass, duration)
2 with shuttle (col) as
3 (select 'Start=0900AM,End=1000AM,Class=1030AM,Duration=60' ||':'||
4 'Start=1100AM,End=1130AM,Class=1015AM,Duration=30' from dual
5 ),
6 tsplit as
7 -- split shuttle value into rows. For multiple selection, values
8 -- are separated by colon. Therefore, you'll have to use something
9 -- different than that - I used the "=" sign and "," to separate columns
10 (select level lvl,
11 regexp_substr(col, '[^:]+', 1, level) val
12 from shuttle
13 connect by level <= regexp_count(col, ':') + 1
14 )
15 -- now split each value to columns. They are separated by commas
16 select lvl,
17 regexp_substr(val, '\w+', 1, 2) cstart,
18 regexp_substr(val, '\w+', 1, 4) cend,
19 regexp_substr(val, '\w+', 1, 6) cclass,
20 regexp_substr(val, '\w+', 1, 8) cduration
21 from tsplit;
2 rows created.
SQL>
SQL> select * From schedule;
ID CSTART CEND CCLASS DURATI
---------- ------ ------ ------ ------
1 0900AM 1000AM 1030AM 60
2 1100AM 1130AM 1015AM 30
SQL>
WITH factoring clause will - in your case - be shuttle item value.
That's all, I presume.

How to check if the length of a string is more than one word and keep only the first word else keep the entire string in SQL?

I have the following table in sql.
I want to keep only the first word in the Name column. I have written the code below however when I run it it extracts the first word for strings longer that one word but returns empty cell for strings which consist of one word only. Could you please advise me how should I modify it to achieve the desired result of keeping only the first word of all strings.
SELECT ID,substr(Name, 1, instr ( Name, ' ' ) -1 ) AS Name FROM names_list
DBMS Toad for Oracle
How about regexp_substr()?
select regexp_substr(name, '^[^ ]+')
from names_list;
This is more flexible than instr(), because you have more control over the separators. For instance, if a comma is sometimes used as well:
select regexp_substr(name, '^[^ ,]+')
from names_list;
This would select the first word out of the name column:
SQL> with names_list (id, name) as
2 (select 1, 'John Smith' from dual union all
3 select 2, 'One' from dual union all
4 select 3, 'Nikola O''Neil' from dual union all
5 select 4, 'Rose Ann Lee' from dual union all
6 select 5, 'Neil' from dual union all
7 select 6, 'William Hugh Forest' from dual union all
8 select 7, 'Andrew' from dual
9 )
10 select id,
11 regexp_substr(name, '^\w+') name
12 from names_list;
ID NAME
---------- --------------------
1 John
2 One
3 Nikola
4 Rose
5 Neil
6 William
7 Andrew
7 rows selected.
SQL>

How do I separate and parse out data from multiple columns into separate rows (Oracle)

I have columns with multiple values delimited by a comma in each column and row. I am trying to separate them out into separate rows. If i have a null value for one of them (as shown below) I will still include the null value as long as one of the other values are still present for that particular row.
What I'm given
First_Name (John, ,Phil)
Last_Name (Smith,No, )
Location (CA,GA,NY)
What I want
(John, Smith, CA)
( , No, GA)
(Phil, ,NY)
I've tried using the regexp_substr method but it's not returning any rows that have a null in any one of the 3 columns listed above.
with
inputs ( id, first_name, last_name, location ) as (
select 101, 'John,,Phil' , 'Smith,No,' , 'CA,GA,NY' from dual union all
select 102, 'Jo,Al,Ed,Li', 'Ng,Tso,,Roth', ',ZZ,,BB' from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select id,
regexp_substr(first_name, '([^,]*)(,|$)', 1, level, null, 1) as first_name,
regexp_substr(last_name , '([^,]*)(,|$)', 1, level, null, 1) as last_name,
regexp_substr(location , '([^,]*)(,|$)', 1, level, null, 1) as location
from inputs
connect by level <= regexp_count(first_name, ',') + 1
and prior id = id
and prior sys_guid() is not null
;
ID FIRST_NAME LAST_NAME LOCATION
---- ----------- ------------ --------
101 John Smith CA
101 No GA
101 Phil NY
102 Jo Ng
102 Al Tso ZZ
102 Ed
102 Li Roth BB
You can try something like this.
SET SERVEROUTPUT ON;
DECLARE
TYPE etype IS TABLE OF VARCHAR2(100);
erec etype;
BEGIN
for rec IN ( SELECT first_name,last_name,location FROM Table1 )
LOOP
WITH fname
AS (SELECT LEVEL lvl,
REGEXP_SUBSTR(rec.first_name, '[^,]+', 1, LEVEL)First_name
FROM DUAL
CONNECT BY REGEXP_SUBSTR(rec.first_name, '[^,]+', 1, LEVEL) IS NOT NULL),
lname
AS (SELECT LEVEL lvl,
REGEXP_SUBSTR(rec.last_name, '[^,]+', 1, LEVEL)Last_Name
FROM DUAL
CONNECT BY REGEXP_SUBSTR(rec.last_name, '[^,]+', 1, LEVEL) IS NOT NULL),
loc
AS (SELECT LEVEL lvl,
REGEXP_SUBSTR(rec.location, '[^,]+', 1, LEVEL)Location
FROM DUAL
CONNECT BY REGEXP_SUBSTR(rec.location, '[^,]+', 1, LEVEL) IS NOT NULL)
SELECT first_name
||','
|| last_name
||','
|| location BULK COLLECT INTO erec
FROM fname fn
FULL OUTER join lname ln
ON fn.lvl = ln.lvl
FULL OUTER join loc lo
ON ln.lvl = lo.lvl;
FOR i IN 1..erec.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(erec(i));
END LOOP;
END LOOP;
END;
/