How to find second value inside a column - sql

How do I list the names of all band members with the same last name?
The column has values like this
band_NAME
-------------------
Carla Thomas
Stephen E. Rice
Cynthia P. Tree
Richard Anthony Paul
Ann Frances Smith
Lorace Black
Timothy Adam Paul
I know we would have to use instr and substr. I just don't get how we would determine the position.
I know the basic format is going to be like
SELECT band_NAME
FROM TABLE
where substr(band_name, ?, instr( ) IN
(select substr(band_name, ?, instr( )-1)
from table
group by SUBSTR(band_NAME , ?, INSTR( )-1 )
HAVING COUNT(* ) > 1 );
But what goes in the question marks and inside the instr?
Would appreciate any help on this!

I'm assuming that your delimiter between first and last name is a single space. More spaces in the string are a part of last name. Thus, you probably want to search for the first space character.
Return position of the first occurence of substring with instr(str, substr).
Then, use substring(str, pos) to return the substring starting at a given position (feed by instr function).
SELECT substring(band_name, instr(band_name, ' '))
FROM yourtable

Try this:
SELECT t1.band_NAME
FROM TABLE t1 LEFT JOIN TABLE t2
ON SUBSTRING_INDEX(t1.band_name, ' ', - 1) = SUBSTRING_INDEX(t2.band_name, ' ', - 1)
WHERE t1.band_name <> t2.band_name
And this like your pseudocode MySQL:
SELECT band_NAME FROM TABLE
Where FIND_IN_SET (SUBSTRING_INDEX(band_name, ' ', -1),
(Select SUBSTRING_INDEX(band_name, ' ', -1) bn
From TABLE Group by bn
having Count(bn) > 1
)
)
SQL Server
SELECT band_NAME FROM TABLE
Where
SUBSTRING(band_NAME, CHARINDEX(' ', band_NAME) + 1, LEN(band_NAME)) AS [Last Name]
IN
(Select SUBSTRING(band_NAME, CHARINDEX(' ', band_NAME) + 1, LEN(band_NAME)) AS [Last Name]
From TABLE Group by [Last Name] -- or SUBSTRING(band_NAME, CHARINDEX(' ', band_NAME) + 1, LEN(band_NAME)) AS [Last Name]
having Count(*) > 1
)
)
Additionally I thinks you can benefit from STRING_SPLIT in some way

Try This
with cte as
(
select band_name, ROW_NUMBER() over(partition by SUBSTRING(band_name,CHARINDEX(' ',band_name),LEN(band_name)) order by band_name) as cnt,
SUBSTRING(band_name,CHARINDEX(' ',band_name),LEN(band_name)) as lastname
from your_table
)
select band_name
from cte
where lastname in (select lastname from cte where cnt > 1)

okay,
The best solution is to change your schema and store last name in a separate column.
In the mean time you could get the last name like this,
SELECT
[band_NAME],
CASE WHEN CHARINDEX(' ', [band_NAME]) > 0
THEN
RIGHT([band_NAME], CHARINDEX(' ', REVERSE([band_NAME])))
ELSE
[band_NAME]
END [LastName]
FROM
[TABLE]
You could then group them like this
SELECT
[LastName],
COUNT(*)
FROM
(
SELECT
[band_NAME],
CASE WHEN CHARINDEX(' ', [band_NAME]) > 0
THEN
RIGHT([band_NAME], CHARINDEX(' ', REVERSE([band_NAME])))
ELSE
[band_NAME]
END [LastName]
FROM
[TABLE]
) [TABLEWithLastName]
GROUP BY
[LastName];

Related

SQL to Take Last Name, First Name and MI and just return First and Last Name

I have searched Stack and getting close to what I need, but can't seem to figure out why when I have a person with just Last Name, First Name that the first name ends up as the Middle Initial? I am only needing the Last Name and First name to display it as First and Last name.
Sample Data:
EMP_ID
EMP_NAME
1234
JONES, JAMES R
5687
SMITH, BILL
What I want to end up with is:
EMP_ID
EMP_NAME_FULL
1234
JAMES JONES
5687
BILL SMITH
I am working with this code and once I can figure out how to resolve getting the first name to work, I planned to combine the First and Last Name substring/Parsing to one name.
SELECT DISTINCT
EMP_ID
,EMP_NAME
,SUBSTRING(EMP_NAME, 1, CHARINDEX(',', EMP_NAME) - 1) AS LASTNAME
,CASE WHEN PARSENAME(REPLACE(EMP_NAME, ',', '.'),1) LIKE '% %' THEN PARSENAME(REPLACE(PARSENAME(REPLACE(EMP_NAME, ',', '.'),1), ' ', '.'),2) ELSE PARSENAME(REPLACE(EMP_NAME, ',', '.'),1) END FIRSTNAME
,CASE WHEN PARSENAME(REPLACE(EMP_NAME, ' ', '.'),1) LIKE '%,%' THEN NULL ELSE PARSENAME(REPLACE(EMP_NAME, ' ', '.'),1) END MI
FROM EMP_TABLE
Try this:
[MYSQL]
select emp_name,
SUBSTRING_INDEX(SUBSTRING_INDEX(emp_name, ', ', -1), ' ', 1),
SUBSTRING_INDEX(emp_name, ',', 1)
from EMP_TABLE;
[MYSQL SSMS]
select emp_name,
CASE
WHEN CHARINDEX(' ', SUBSTRING(emp_name, CHARINDEX(', ',emp_name)+2)) >0
THEN SUBSTRING(SUBSTRING(SUBSTRING(emp_name, CHARINDEX(', ',emp_name)+2), ' '),1,CHARINDEX(' ',SUBSTRING(emp_name, CHARINDEX(', ',emp_name)+2)))
ELSE SUBSTRING(SUBSTRING(emp_name, CHARINDEX(', ',emp_name)+2), ' ')
END AS firstname,
SUBSTRING(emp_name, 1, CHARINDEX(',',emp_name) - 1) AS lastname
from EMP_TABLE;
I couldn't try it with MYSQL SSMS but the function CHARINDEX is the same as INSTR, the only difference is in INSTR you specify first where to look and then what to look.
I try it like this with your data and it worked.
Then, I convert every INSTR into CHARINDEX, and I inverted the parameters.
[DEMO]
with tmp as
(
select 'JONES, JAMES R' as emp_name from dual
union all
select 'SMITH, BILL' as emp_name from dual
)
select emp_name,
CASE
WHEN INSTR(SUBSTRING(emp_name, INSTR(emp_name,', ')+2),' ') >0
THEN SUBSTRING(SUBSTRING(SUBSTRING(emp_name, INSTR(emp_name,', ')+2), ' '),1,INSTR(SUBSTRING(emp_name, INSTR(emp_name,', ')+2),' '))
ELSE
SUBSTRING(SUBSTRING(emp_name, INSTR(emp_name,', ')+2), ' ')
END AS firstname,
SUBSTRING(emp_name, 1, INSTR(emp_name,',') - 1) AS lastname
from tmp;

Separate fullname into first and last, and remove 'junk'

Wasn't sure of the best way to word this. So I have a column with names, as below:
SalesPerson_Name
----------------
Undefined - 0
Sam Brett-sbrett
Kelly Roberts-kroberts
Michael Paramore-mparamore
Alivia Lawler-alawler
Ryan Hooker-rhooker
Heather Alford-halford
Cassandra Blegen-cblegen
JD Holland-jholland
Vendor Accounts-VENDOR
Other Accounts-OTHER
Getting the names separated is easy enough with PARSENAME and REPLACE functions, but where I'm running into a pickle is with getting rid of the 'junk' at the end:
SELECT SalesPerson_Key
,SalesPerson_Name
,CASE
WHEN PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 2) IS NULL
THEN PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 1)
ELSE PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 2)
END AS FirstName
,CASE
WHEN PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 2) IS NULL
THEN NULL
ELSE PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 1)
END AS LastName
FROM Salesperson
RESULTS FOR LASTNAME COLUMN:
LastName
--------
0
Brett-sbrett
Roberts-kroberts
Paramore-mparamore
Lawler-alawler
Hooker-rhooker
Alford-halford
Blegen-cblegen
Holland-jholland
Accounts-VENDOR
Accounts-OTHER
Specifically, I want to get rid of the text (userid) at the end of the last name. If the names were the same length, I could just use a RIGHT function, but they vary in length. Ideas?
select left(PARSENAME(REPLACE(SalesPerson_Name, ' ', '.'), 1), len(SalesPerson_Name)-CHARINDEX('-',SalesPerson_Name)-1)
You are getting charindex of - and taking the left string of it.
If you just want to remove the last word (username) you can use a query like this
select
rtrim(
substring(
SalesPerson_Name,
1,
charindex('-',SalesPerson_Name,1)-1
)
)
from Salesperson
The charindex function locates the occurrence of the character/s you are looking for.
Consider whether hyphen is followed by a space or not, and split depending on these two cases
with Salesperson( SalesPerson_Name ) as
(
select 'Undefined - 0' union all
select 'Sam Brett-sbrett' union all
select 'Kelly Roberts-kroberts' union all
select 'Michael Paramore-mparamore' union all
select 'Alivia Lawler-alawler'
)
select case when substring(SalesPerson_Name,charindex(' ',SalesPerson_Name)+1,1) = '-' then
substring(SalesPerson_Name,charindex(' ',SalesPerson_Name)+3,len(SalesPerson_Name))
else
substring(SalesPerson_Name,charindex(' ',SalesPerson_Name)+1,len(SalesPerson_Name))
end as last_name
from Salesperson s;
last_name
------------------
0
Brett-sbrett
Roberts-kroberts
Paramore-mparamore
Lawler-alawler

SQL Server : to get last 4 character in first column and get the first letter of the words in 2nd column but ignore non alphabets

Can I check will it be possible to run SQL with this requirement? I trying to get a new value for new column from these 2 existing columns ID and Description.
For ID, simply retrieve last 4 characters
For Description, would like to get the first alphabets for each word but ignore the numbers & symbols.
SQL Server has lousy string processing capabilities. Even split_string() doesn't preserve the order of the words that it finds.
One approach to this uses a recursive CTE to split the strings and accumulate the initials:
with t as (
select v.*
from (values (2004120, 'soccer field 2010'), (2004121, 'ruby field')) v(id, description)
),
cte as (
select id, description, convert(varchar(max), left(description, charindex(' ', description + ' '))) as word,
convert(varchar(max), stuff(description, 1, charindex(' ', description + ' ') , '')) as rest,
1 as lev,
(case when description like '[a-zA-Z]%' then convert(varchar(max), left(description, 1)) else '' end) as inits
from t
union all
select id, description, convert(varchar(max), left(rest, charindex(' ', rest + ' '))) as word,
convert(varchar(max), stuff(rest, 1, charindex(' ', rest + ' ') , '')) as rest,
lev + 1,
(case when rest like '[a-zA-Z]%' then convert(varchar(max), inits + left(rest, 1)) else inits end) as inits
from cte
where rest > ''
)
select id, description, inits + right(id, 4)
from (select cte.*, max(lev) over (partition by id) as max_lev
from cte
) cte
where lev = max_lev;
Here is a db<>fiddle.
To get the last 4 numbers of the ID you could use:
SELECT Id%10000 as New_Id from Tablename;
To get the starting of each Word you could use(letting the answer be String2):
LEFT(Description,1)
This is equivalent to using SUBSTRING(Description,1,1)
This helps you get the first letter of each word.
To concatenate both of them you could use the CONCAT function:
SELECT CONCAT(String2,New_Id)
See more on the CONCAT function here

SQL - re.split: BY comma THEN space

I want to split the following string into City, Province, Postal Code.
Thank you so much for the help!!!!
Description: Split by comma, then split by space only once.
A = 'Vaughan, ON L6D 9X0'
Result:
(Vaughan, ON, L6D9X0)
Attempt:
re.split(',|/s[1]', A)
Try This,
This selected the values into rows, maybe you can pivot the cte C2 same in order to get it as columns
WITH CTE
AS
(
SELECT
1 Seq,
'Vaughan, ON L6D 9X0' "Txt"
UNION ALL
SELECT
Seq+1 "Seq",
Txt = CASE WHEN Txt LIKE '% %'
THEN LTRIM(RTRIM(SUBSTRING(Txt,CHARINDEX(' ',Txt),LEN(Txt))))
ELSE NULL END
FROM CTE
WHERE ISNULL(txt,'')<>''
),C2
AS
(
SELECT
CASE Seq
WHEN 1 THEN 'City'
WHEN 2 THEN 'Province'
ELSE 'PostalCode' END "Head",
CASE Seq
WHEN 1
THEN SUBSTRING(Txt,1,CHARINDEX(',',Txt)-1)
WHEN 2
THEN SUBSTRING(Txt,1,CHARINDEX(' ',Txt)-1)
ELSE Txt END "Txt"
FROM CTE
WHERE Seq<4
)
SELECT
*
FROM C2;
If you have multiple rows that need to be parsed in the same way then, you can give the same in the select statement of 1st CTE and in that case, the logic for Seq on the first select might need to be changed. As per the above, the output will be as follows
With Postgres you can do that using:
select split_part(a, ',', 1) as city,
left(trim(split_part(a,',',2)), strpos(trim(split_part(a,',',2)), ' ')),
substr(trim(split_part(a,',',2)) as province, strpos(trim(split_part(a,',',2)), ' ') + 1) as postal_code
from the_table;
This can be made a bit more readable by using a derived table:
select city,
left(second_part, strpos(second_part, ' ')) as province,
substr(second_part, strpos(second_part, ' ') + 1) as postal_code
from (
select split_part(a, ',', 1) as city,
trim(split_part(a, ',', 2)) as second_part
from the_table
) t
IF, You are working with Microsoft SQL Server, then you could use SUBSTRING() &CHARINDEX() function to find specific Char index to split the string values.
SELECT SUBSTRING(<column>, 1, CHARINDEX(',', <column>)-1) City,
SUBSTRING(SUBSTRING(<column>, CHARINDEX(' ', <column>)+1, LEN(<column>)), 1, CHARINDEX(' ', SUBSTRING(<column>, CHARINDEX(' ', <column>)+1, LEN(<column>)))) Province,
SUBSTRING(SUBSTRING(<column>, CHARINDEX(' ', <column>)+1, LEN(<column>)), CHARINDEX(' ', SUBSTRING(<column>, CHARINDEX(' ', <column>)+1, LEN(<column>)))+1, LEN(<column>)) [Postal Code];
Desired Output :
City Province Postal Code
Vaughan ON L6D 9X0

How to get middle portion from Sql server table data?

I am trying to get First name from employee table, in employee table full_name is like this: Dow, Mike P.
I tried with to get first name using below syntax but it comes with Middle initial - how to remove middle initial from first name if any. because not all name contain middle initial value.
-- query--
select Employee_First_Name as full_name,
SUBSTRING(
Employee_First_Name,
CHARINDEX(',', Employee_First_Name) + 1,
len(Employee_First_Name)) AS FirstName
---> remove middle initial from right side from employee
-- result
Full_name Firstname Dow,Mike P. Mike P.
--few example for Full_name data---
smith,joe j. --->joe (need result as)
smith,alan ---->alan (need result as)
Instead of specifying the len you need to use charindex again, but specify that you want the second occurrence of a space.
select Employee_First_Name as full_name,
SUBSTRING(
Employee_First_Name,
CHARINDEX(',', Employee_First_Name) + 1,
CHARINDEX(' ', Employee_First_Name, 2)) AS FirstName
One thing to note, the second charindex can return 0 if there is no second occurence. In that case, you would want to use something like the following:
select Employee_First_Name as full_name,
SUBSTRING(
Employee_First_Name,
CHARINDEX(',', Employee_First_Name) + 1,
IIF(CHARINDEX(' ', Employee_First_Name, 2) = 0, Len(Employee_First_name), CHARINDEX(' ', Employee_First_Name, 2))) AS FirstName
This removes the portion before the comma.. then uses that string and removes everything after space.
WITH cte AS (
SELECT *
FROM (VALUES('smith,joe j.'),('smith,alan'),('joe smith')) t(fullname)
)
SELECT
SUBSTRING(
LTRIM(SUBSTRING(fullname,CHARINDEX(',',fullname) + 1,LEN(fullname))),
0,
COALESCE(NULLIF(CHARINDEX(' ',LTRIM(SUBSTRING(fullname,CHARINDEX(',',fullname) + 1,LEN(fullname)))),0),LEN(fullname)))
FROM cte
output
------
joe
alan
joe
To be honest, this is most easily expressed using multiple levels of logic. One way is using outer apply:
select ttt.firstname
from t outer apply
(select substring(t.full_name, charindex(', ', t.full_name) + 2, len(t.full_name) as firstmi
) tt outer apply
(select (case when tt.firstmi like '% %'
then left(tt.firstmi, charindex(' ', tt.firstmi)
else tt.firstmi
end) as firstname
) as ttt
If you want to put this all in one complicated statement, I would suggest a computed column:
alter table t
add firstname as (stuff((case when full_name like '%, % %.',
then left(full_name,
charindex(' ', full_name, charindex(', ', full_name) + 2)
)
else full_name
end),
1,
charindex(', ', full_name) + 2,
'')
If format of this full_name field is the same for all rows, you may utilize power of SQL FTS word breaker for this task:
SELECT N'Dow, Mike P.' AS full_name INTO #t
SELECT display_term FROM #t
CROSS APPLY sys.dm_fts_parser(N'"' + full_name + N'"', 1033, NULL, 1) p
WHERE occurrence = 2
DROP TABLE #t