Split Name into Last name, First Name, Middle Name in SQL - sql

I have a record below. I want to split the name into Lname, Fname, Mname
Name
John, David Handsome
Here is my query. I was able to get Lname but not Fname and Mname yet.
SELECT
NAME,
LEFT(NAME,CHARINDEX(',',NAME)-1) AS LNAME
FROM TABLE
My desired output would be:
Name Lname Fname Mname
John, David Handsome John Daivd Handsome

If the format of name is gonna remain the same then use below :
select name,LEFT(NAME,CHARINDEX(',',NAME)-1) AS LNAME, regexp_substr(name,'[^ ]+',1,2) as fname,regexp_substr(name,'[^ ]+',1,3) mname from table;

You can do it like this;
SELECT
LEFT(NAME,CHARINDEX(',',NAME)-1) AS LNAME,
LEFT(REPLACE(NAME,LEFT(NAME,CHARINDEX(',',NAME)+1),''),CHARINDEX(' ',REPLACE(NAME,LEFT(NAME,CHARINDEX(',',NAME)+1),''))-1) AS FNAME,
REPLACE(REPLACE(NAME,LEFT(NAME,CHARINDEX(',',NAME)+1),''),LEFT(REPLACE(NAME,LEFT(NAME,CHARINDEX(',',NAME)+1),''),CHARINDEX(' ',REPLACE(NAME,LEFT(NAME,CHARINDEX(',',NAME)+1),''))-1),'') AS MNAME
It comes little confusing because of nested replace and charindex functions. But if you focus on them closely, logic is quite simple.

Related

To Merge two rows using SQL

I am stuck in a situation where with my SQL query I am getting an output as below.
I want my output to be of single row so that the end user have a glance at the report and can easily guess which are the event that guy has attended as below.
If you want a single row, use GROUP BY:
select fname, lname, max(event1) as Event1, max(event2) as event2
from t
group by fname, lname;
Assuming that every person has events including both yes and no, you can use below query to generate your desired result. If both values are no, you will get no in result then.
SELECT fname,
lname,
max(event1) as event1,
max(event2) as event2
FROM t1
GROUP BY fname,
lname;
Result:
fname lname event1 event2
------------------------------
abc xyz yes yes
you can check the demo here

Querying for swapped columns in SQL database

We've had a few cases of people entering in first names where last names should be and vice versa. So I'm trying to come up with a SQL search to match the swapped columns. For example, someone may have entered the record as first_name = Smith, last_name = John by accident. Later, another person may see that John Smith is not in the database and enter a new user as first_name = John, last_name = Smith, when in fact it is the same person.
I used this query to help narrow my search:
SELECT person_id, first_name, last_name
FROM people
WHERE first_name IN (
SELECT last_name FROM people
) AND last_name IN (
SELECT first_name FROM people
);
But if we have people named John Allen, Allen Smith, and Smith John, they would all be returned even though none of those are actually duplicates. In this case, it's actually good enough that I can see the duplicates in my particular data set, but I'm wondering if there's a more precise way to do this.
I would do a self join like this:
SELECT p1.person_id, p1.first_name, p1.last_name
FROM people p1
join people p2 on p1.first_name = p2.last_name and p1.last_name = p2.first_name
To also find typos on names I recommend this:
SELECT p1.person_id, p1.first_name, p1.last_name
FROM people p1
join people p2 on soundex(p1.first_name) = soundex(p2.last_name) and
soundex(p1.last_name) = soundex(p2.first_name)
soundex is a neat function that "hashes" words in a way that two words that sound the same get the same hash. This means Anne and Ann will have the same soundex. So if you had an Anne Smith and a Smith Ann the query above would find them as a match.
Interesting. This is a problem that I cover in Data Analysis Using SQL and Excel (note: I only very rarely mention books in my answers or comments).
The idea is to summarize the data to get a likelihood of a mismatch. So, look at the number of times a name appears as a first name and as a last name and then combine these. So:
with names as (
select first_name as name, 1.0 as isf, 0.0 as isl
from people
union all
select last_name, 0, 1
from people
),
nl as (
select name, sum(isf) as numf, sum(isl) as numl,
avg(isf) as p_f, avg(isl) as p_l
from names
group by name
)
select p.*
from people p join
nl nlf
on p.first_name = nlf.name join
nl nll
on p.last_name = nll.name
order by (coalesce(nlf.p_l, 0) + coalesce(nll.p_f, 0));
This orders the records by a measure of mismatch of the names -- the sum of the probabilities of the first name used by a last name and a last name used as a first name.

Can I use COUNT() function in the WHERE clause? Query about Presidents

I have a relation Presidents(firstName,lastName,beginTerm,endTerm)
that gives information about US Presidents. Attribute firstName is a string
with the first name, and in some cases, one or more
middle initials.
Attribute lastName is a string with the last name of the president. For example,
the previous president has firstName = 'George W.' and his father has firstName = 'George H.W.'; both have lastName = 'Bush'. The last 2 attributes, beginTerm and endTerm,
are the years the president entered and left office, respectively.
One subtlety is that Grover Cleveland served 2 noncontiguous
terms. He appears in 2 tuples, one with the beginning and ending years of his first term and the other for the second term.
The question I have is below:
There are 2 pairs of presidents that were father and son. But there are
a number of other pairs of presidents that shared a last name. Find all the last names belonging to 2 or more Presidents. Do not repeat a last name, and remember that the same person serving 2 different terms (e.g., Grover Cleveland) does not constitute a case of 2 presidents with the same last name.
I first thought the answer might be:
SELECT lastName
FROM Presidents
WHERE COUNT(lastName) > 2
EXCEPT lastName = 'Cleveland';
I'm not too sure if the COUNT() function can be used in the WHERE clause though.
Is this possible?
Thanks!
Use HAVING instead of WHERE when checking against Group functions.
SELECT lastName
FROM Presidents
WHERE lastName != 'Cleveland'
GROUP BY lastName
HAVING COUNT(lastName) > 2;
However, when solving SQL-puzzles likes this, you should never take into account the actual data. It should work for all consistent data-sets! I believe this is an actual solution to your problem:
SELECT DISTINCT p1.lastName
FROM Presidents p1, Presidents p2
WHERE p1.lastName == p2.LastName
AND p1.firstName != p2.firstName;
You constrain on aggregates using HAVING, and you are also missing a group by.
SELECT lastName
FROM Presidents
where lastName <> 'Cleveland';
group by lastname
having COUNT(lastName) > 2
Assuming there is an id field as well,
select id, lastname, count(*) differentguycount
from presidents left join
(select id, firstname, lastname count(*) sameguycount
from presidents
group by id, firstname, lastname
having sameguycount > 1 ) temp on temp.id = presidents.id
where temp.firstname is null
group by id, lastname
having differentguycount > 1
As noted, the OP did not specify his database engine which could cause syntax errors. For example some databases might not allow you to use aliases in the having clause.

Ordering 2 columns on the same order

I have the table:
Example:
Name | Last Name
Albert Rigs
Carl Dimonds
Robert Big
Julian Berg
I need to order like this:
Name | Last Name
Albert Rigs (name)
Julian Berg (last name)
Robert Big (last name)
Carl Dimonds
I need something like, order by name and last name on the same ordering.
See on example, i have Name Albert, the next ordered name row its the Carl, but i have Big and Berg on last name, B > C so i get the last name order on second row.
It's like the two columns are the same but isn't.
It's hard to explaim, i'm sorry.
Its possible?
Thaks in advance.
To order by the minimum of (Name, Lastname), you could:
select *
from YourTable
order by
case
when Name > LastName then LastName
else name
end
A syntactic improvement on the Case, and allowing a ti-break on the other column.
select *
from my_table
order by least(name,last_name),
greatest(name,last_name)

T-SQL Query Problem

I have a column in Database called Full Name and I want split that name as FirstName and LastName:
Here is an Example:
FullName
Sam Peter
I want this to be
FirstName LastName
--------------------
Sam Peter
But the Problem is Some of the columns in Database have Full Names Like this
FullName
--------
Sam George Jack Peter
Sam Adam Peter
I want this to be
FirstName LastName
--------- --------
Sam George Jack Peter
Sam Adam Peter
How do I write T-SQL Query for this.
Thanks in Advance for all the help
There's a very thorough name parsing routine described in this answer. It handles your situation, along with much trickier cases like "Mr. Martin J Van Buren III".
String manipulation in SQL Server is notoriously weak.
Your best bet is to do it in your application layer.
For your example with more than 2 names, how do you know which fields those additional names go into? Are you guaranteed they will always have only one last name?
Found this on net (did not test it)
REVERSE(SUBSTRING(REVERSE([FullName]),1,FINDSTRING(REVERSE([FullName])," ",1)))
You can test it with
SELECT REVERSE(SUBSTRING(REVERSE([FullName]),1,FINDSTRING(REVERSE([FullName])," ",1)))
FROM Table
if it works you can then
UPDATE Table
SET LastName = REVERSE(SUBSTRING(REVERSE([FullName]),1,FINDSTRING(REVERSE([FullName])," ",1)))
I leave the exercise for the first name to you.
Are you just splitting at the last space? If so this should work:
select 'Sam George Jack Peter' as FullName
into #names
union select 'Sam Adam Peter'
select LEFT(FullName,LEN(FullName)-CHARINDEX(' ',REVERSE(FullName))) as FirstName
,RIGHT(FullName,CHARINDEX(' ',REVERSE(FullName))-1) as LastName
from #names
EDIT:
To handle names with no spaces and put the FullName as LastName
select 'Sam George Jack Peter' as FullName
into #names
union select 'Sam Adam Peter'
union select 'Peter'
select CASE
WHEN CHARINDEX(' ',FullName) = 0 THEN ''
ELSE LEFT(FullName,LEN(FullName)-CHARINDEX(' ',REVERSE(FullName)))
END as FirstName
,CASE
WHEN CHARINDEX(' ',FullName) = 0 THEN FullName
ELSE LTRIM(RIGHT(FullName,CHARINDEX(' ',REVERSE(FullName))))
END as LastName
from #names