How do I split entire full name column in Oracle [duplicate] - sql

This question already has answers here:
Split varchar into separate columns in Oracle
(3 answers)
Closed 5 months ago.
In Oracle, I've got a full name column. I want to split that into a first name column and a last name column. SQL code?

If it's not working for all rows, then your rows have different delimiters.
with my_data as (
select 'john smith' as full_name from dual union all
select 'rudy chan' from dual union all
select 'h gonzalez' from dual
)
SELECT full_name,
SUBSTR(full_name, 1, INSTR(full_name, ' ')-1) AS first_name,
SUBSTR(full_name, INSTR(full_name, ' ')+1) AS last_name
FROM my_data
FULL_NAME
FIRST_NAME
LAST_NAME
john smith
john
smith
rudy chan
rudy
chan
h gonzalez
h
gonzalez
fiddle
UPDATE
Based on your comments below, you are looking for how to ADD columns to a table. Broke this out into two steps....
--adding two columns
Alter table my_data
add (
first_name varchar(20),
last_name varchar(20)
);
--update the newly added columns
update my_data
set first_name = SUBSTR(full_name, 1, INSTR(full_name, ' ')-1),
last_name = SUBSTR(full_name, INSTR(full_name, ' ')+1);
select *
from my_data
FULL_NAME
FIRST_NAME
LAST_NAME
john smith
john
smith
rudy chan
rudy
chan
h gonzalez
h
gonzalez

Isolated's option is just fine (according to the task); another option might be regular expressions.
It looks simpler and works OK on small data sets, such as your table with 40 rows; for large tables, e.g. hundreds of millions rows, substr + instr combination will most probably work way faster.
Sample data:
SQL> select * from my_data;
FULL_NAME FIRST_NAME LAST_NAME
---------- -------------------- --------------------
john smith
rudy chan
h gonzalez
Query:
SQL> update my_data set
2 first_name = regexp_substr(full_name, '^\w+'),
3 last_name = regexp_substr(full_name, '\w+$');
3 rows updated.
Result:
SQL> select * from my_data;
FULL_NAME FIRST_NAME LAST_NAME
---------- -------------------- --------------------
john smith john smith
rudy chan rudy chan
h gonzalez h gonzalez
SQL>

Related

How to return a count of duplicates and unique values into a column in Access

I currently have this table:
First_Name
Last_Name
Jane
Doe
John
Smith
Bob
Smith
Alice
Smith
And I'm looking to get the table to look for duplicates in the last name and return a value into a new column and exclude any null/unique values like the table below, or return a Yes/No into the third column.
First_Name
Last_Name
Duplicates
Jane
Doe
0
John
Smith
3
Bob
Smith
3
Alice
Smith
3
OR
First_Name
Last_Name
Duplicates
Jane
Doe
No
John
Smith
Yes
Bob
Smith
Yes
Alice
Smith
Yes
When I'm trying to enter the query into the Access Database, I keep getting the run-time 3141 error.
The code that I tried in order to get the first option is:
SELECT first_name, last_name, COUNT (last_name) AS Duplicates
FROM table
GROUP BY last_name, first_name
HAVING COUNT(last_name)=>0
You can use a subquery. But I would recommend 1 instead of 0:
select t.*,
(select count(*)
from t as t2
where t2.last_name = t.last_name
)
from t;
If you really want zero instead of 1, then one method is:
select t.*,
(select iif(count(*) = 1, 0, count(*))
from t as t2
where t2.last_name = t.last_name
)
from t;

Comparing string values within a table

Is there any way to compare two columns with strings to each other, and getting the matches?
I have two columns containing Names, once with the Full Name the other with (mostly) just the Surname.
I just tried it with soundex, but it will just return if the values are almost similar in both columns.
SELECT * FROM TABLE
WHERE soundex(FullName) = soundex(Surname)
1 John Doe Doe
2 Peter Parker Parker
3 Brian Griffin Brian Griffin
with soundex it will only match the 3rd line.
A simple option is to use instr, which shows whether surname exists in fullname:
SQL> with test (id, fullname, surname) as
2 (select 1, 'John Doe' , 'Doe' from dual union all
3 select 2, 'Peter Parker' , 'Parker' from dual union all
4 select 3, 'Brian Griffin', 'Brian Griffin' from dual
5 )
6 select *
7 from test
8 where instr(fullname, surname) > 0;
ID FULLNAME SURNAME
---------- ------------- -------------
1 John Doe Doe
2 Peter Parker Parker
3 Brian Griffin Brian Griffin
Another option is to use one of UTL_MATCH functions, e.g. Jaro-Winkler similarity which shows how well those strings match:
SQL> with test (id, fullname, surname) as
2 (select 1, 'John Doe' , 'Doe' from dual union all
3 select 2, 'Peter Parker' , 'Parker' from dual union all
4 select 3, 'Brian Griffin', 'Brian Griffin' from dual
5 )
6 select id, fullname, surname,
7 utl_match.jaro_winkler_similarity(fullname, surname) jws
8 from test
9 order by id;
ID FULLNAME SURNAME JWS
---------- ------------- ------------- ----------
1 John Doe Doe 48
2 Peter Parker Parker 62
3 Brian Griffin Brian Griffin 100
SQL>
Feel free to explore other function that package offers.
Also, note that I didn't pay attention to possible letter case differences (e.g. "DOE" vs. "Doe"). If you need that as well, compare e.g. upper(surname) to upper(fullname).
Please use instring function,
SELECT * FROM TABLE
WHERE instr(Surname, FullName) > 0;
SELECT * FROM TABLE
WHERE instr(upper(Surname), upper(FullName)) > 0;
SELECT * FROM TABLE
WHERE upper(FullName) > upper(Surname);
As far as I know there is nothing out of the box when matching becomes complicated. For the cases shown, however, the following expression would suffice:
where fullname like '%' || surname
Update
The main problem may be false positives:
The last name 'Park' appears in 'Peter Parker'. Above query solves this by looking at the full name's end.
Another problem may be upper / lower case as mentioned in the other answers (not shown in your sample data).
You want the last name 'PARKER' match 'Peter Parker'.
But when looking at the strings case insensitively, another problem arises:
The last name 'Strong' will suddenly match 'Louis Armstrong'.
A solution for this is to add a blank to make the difference:
where ' ' || upper(fullname) like '% ' || upper(surname)
' LOUIS ARMSTRONG' like '% STRONG' -> false
' LOUIS ARMSTRONG' like '% ARMSTRONG' -> true
' LOUIS ARMSTRONG' like '% LOUIS ARMSTRONG' -> true
Demo: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=0ac5c80061b4aeac1153a8c5976e6e54

Oracle Statement to Return Result Depending on Max Value of a Record

I've been stuck here for the whole day.
I have 2 tables:
TABLE 1: LOGS
FIRST_NAME LAST_LOG_IN
------------------------------
John 15-NOV-17
Jane 13-NOV-17
John 12-NOV-17
John 11-NOV-17
John 10-NOV-17
Jane 12-NOV-17
TABLE 2: USER
FIRST_NAME LAST_NAME
------------------------------
Jane Doe
John Smith
The Requirements are:
If today is 22-NOV-17, I need to get the FIRST_NAME, LAST_NAME
and LAST_LOG_IN(in 'YYYY-MM-DD HH24:MI:SS' format) of the user
only if his/her LAST_LOG_IN is earlier than the last 7 days
Put only in one statement to execute in SQL Developer (not using PL/SQL)
so the Expected Output should be:
FIRST_NAME LAST_NAME LAST_LOG_IN
---------------------------------------------------
Jane Doe 2017-11-13 17:49:57
Something like:
select u.first_name, u.last_name, to_char(a.log_date,'YYYY-MM-DD HH24:MI:SS') from (
select first_name, max(last_log_in) log_date from logs group by first_name) a
inner join
user u on (a.first_name = u.first_name)
where a.log_date > sysdate - 7;

Format result from SQL query

I am learning SQL with Oracle. I have query that shows 3 columms from a table called people: show last name, first name . I want to display another column that indicates that if there is phone number to show it and if it is null to show it as XXX-XXX-XXXX. So far my query shows the information but not in the format that i want.
Select last_name, first_name, phone_number AS phone_Num from people
Results:
LAST_NAME FIRST_NAME PHONE_NUM
---------------- ---------------- ------------
Doe Fred
Hanes Tina 123-587-9087
Douglas Tim
McCarthy Bob 212-098-9876
Desired:
LAST_NAME FIRST_NAME PHONE_NUM HAS_PHONE_NUM
---------------- ---------------- ------------ -------------
Doe Fred XXX-XXX-XXXX
Hanes Tina 123-587-9087 123-587-9087
Douglas Tim XXX-XXX-XXXX
McCarthy Bob 212-098-9876 212-098-9876
You can use COALESCE function:
Try this:
Select last_name, first_name, phone_number AS phone_Num,
coalesce(phone_number, 'XXX-XXX-XXXX') as HAS_PHONE_NUM from people
Or use NVL :
Select last_name, first_name, phone_number AS phone_Num,
nvl(phone_number, 'XXX-XXX-XXXX') as HAS_PHONE_NUM from people
COALESCE is a part of ANSI-92 standard and NVL is Oracle specific.
Use Case Statement
SELECT last_name,
first_name,
phone_number AS phone_Num,
CASE
WHEN phone_number = '' THEN 'XXX-XXX-XXXX' --or Lenght(phone_number) = 0
ELSE phone_number
END AS HAS_PHONE_NUM
FROM people

pl/sql query to remove duplicates and replace the data

I have the following table:
data_id new_data_id first_name last_name
1 john smith
2 john smith
3 john smith
4 jeff louis
5 jeff louis
6 jeff louis
The above table has duplicate first and last names, and the data_id is different for all of them. In order to remove these duplicates, I would need to write a SQL query to replace the highest data_id in new_data_id column. My output would look something like this:
data_id new_data_id first_name last_name
1 3 john smith
2 3 john smith
3 3 john smith
4 6 jeff louis
5 6 jeff louis
6 6 jeff louis
How would I do this?
What you're looking for is an Oracle analytic function.
The aggregate function MAX can be used to select the highest data_id from your entire resultset, but that's not exactly what you need. Instead, use its alter ego, the MAX analytic function like so:
SELECT
data_id,
MAX(data_id) OVER (PARTITION BY first_name, last_name) AS new_data_id,
first_name,
last_name
FROM employees
ORDER BY data_id
This works by "partitioning" your resultset by first_name and last_name, and then it performs the given function within that subset.
Good luck!
Here's a fiddle: http://sqlfiddle.com/#!4/48b29/4
More info can be found here:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions004.htm#SQLRF06174
If you need a change in place, a correlated update is probably the simplest way to write that:
UPDATE T
SET "new_data_id" =
(SELECT MAX("data_id") FROM T T2
WHERE T2."first_name" = T."first_name"
AND T2."last_name" = T."last_name")
See http://sqlfiddle.com/#!4/51a69/1