SQL select specific letter from concatenated string - sql

This may have been answered similarly somewhere but I am still kind of confused. I need to create a view named A7T7 that will display the concatenated first name and last name of the students who have at least three letter Os or three letter Ts in their concatenated name (e.g., John Olson, Richard Hooton, Tina Trout). The column heading should be Student and the rows should be sorted by the length of the concatenated names from long to short.
Not really sure how to make my WHERE statement for this restriction.

You can use a LIKE query - for example (using a table variable for SQL Server):
CREATE TABLE #students (firstname varchar(20), lastname varchar(20));
INSERT ALL
INTO #students VALUES ('John','Olson')
INTO #students VALUES ('Richard','Hooton')
INTO #students VALUES ('Tina','Trout')
SELECT 1 FROM dual;
SELECT *
FROM #students s
WHERE CONCAT(s.firstname, s.lastname) LIKE '%o%o%o%';
DROP TABLE #students;
Which roughly translates to "select all the rows from students where the concatenation of firstname and lastname contains o three times".

Related

How select an aggregated row in SQL?

I have a table with aggregated columns like this in a SQL Server. The goal is: Show me any row that contains Street A or B.
Name
Adresses
Mike
Street A, Street B, Street C
Smith
Street B
Jimmy
Street C
Declare #street table (col nvarchar (50) )
INSERT INTO #street Values ('Street A'), ('Street B' )
SELECT *
FROM Table
WHERE Adresses like '%' + #street + '%'
SELECT *
FROM Table
WHERE Adresses = ( SELECT * FROM #street )
SELECT *
FROM Table
WHERE STRING_SPLIT(Adresses,',') in ( SELECT * FROM #street )
It does not work. I do not get results. The results should be like this:
Name
Adresses
Mike
Street A, Street B, Street C
Smith
Street B
You should get rid of this bad structure and store the data in a better form in future.
Anyway, following your intention to use STRING_SPLIT for that, this would do:
SELECT name, adresses
FROM yourtable
WHERE EXISTS
(SELECT *
FROM STRING_SPLIT(adresses, ',')
WHERE value IN ('Street A', 'Street B'));
You should read the documentation, that's explained there.
Testing with your sample data succeeds: db<>fiddle
I am sure you can use some "contains" functionality on column adresses. Depends if the column is a varchar/text like column, or a array like column.
However, i would instead try to solve this in a more conseptual level.
In relational databases, this would be referred as a "many to one" relationship.
One adress may have only one Persons related to them, while the Person may have listed many Adresses.
Therefore i would make seperate tables. Then you can easily Search the Adresses table for A and B and find related foreign keys to Persons table.
Otherwise, you can insist on using "contains" functionality, but this might get computationally expensive.

inserting multiples values in one column

I have a question about SQL. I have created a table in SQL with only one column containing the name of two people (say John and Matt). Later I added a new column into the table with ALTER TABLE. This column will contain the surname of these people.
My question is, in case mmy table contained several people already is there a command to enter the surnames for all the people at once rather than writing one command for each person as in:
INSERT INTO table (Surname) VALUE (John's surname) and
INSERT INTO table (Surname) VALUE (Matt's surname) ?
Thanks in advance
P.D.
I tried something like:
UPDATE foo set Surname=("Parker","Walker") where Name =("John","Matt") but does not work
You want an update. Something like this:
update t
set surname = 'John'' surname'
where firstname = 'John';
You can do this separately for each name. Or use a case expression for multiple ones:
UPDATE foo
SET Surname = (CASE WHEN Name = 'John' THEN 'Parker'
WHEN Name = 'Matt' THEN 'Walker'
END)
WHERE Name IN ('John', 'Matt');

TSQL: Find part of string based on a column in temp table

I need to extract the school name from a file name string. I put all of the schools in a temp table and I need to use the temp table column of SchoolName to search the string. This filename is inherited and should be a one time event to try to extract data from.
The SchoolCode and SchoolName are in the temp table. If the SchoolName matches what's in the temp table, I would like the SchoolCode as well.
I tried doing a subquery in the WHERE clause but I get an error stating it returned more than one result.
Current data:
Desired Result:
Test Code:
DROP TABLE #SchoolName
GO
CREATE TABLE #SchoolName (
FILENAME VARCHAR(MAX)
)
INSERT INTO #SchoolName
( FILENAME )
VALUES
('New Student added 10-02-16\High School\2015\North Side HS\JONES, JIMMY E_07-29-1993_2314687.PDF')
,('2006\South Side HIGH SCHOOL\GRADUATE\Johnson Jack B,03-19-1989,7123444.PDF')
,('2010\Riverwood\GRADUATES\Harmon, Kardon C_07-21-1991_370143.PDF')
,('2009\RockCreek\GRADUATES\Vandolay, Art E_09-23-1974_7210122.PDF')
DROP TABLE #SchoolsList
CREATE TABLE #SchoolsList (
SchoolCode VARCHAR(4)
,School varchar(500)
)
INSERT INTO #SchoolsList
(
SchoolCode
, School
)
VALUES
(1111 ,'North Side '),(1112 ,'South Side '),(1113 ,'Riverwood '),(1114 ,'RockCreek')
You can join to your SchoolList table using a like (assuming your school list is actually a distinct list)
SELECT l.SchoolCode, n.*
FROM #SchoolName n
LEFT OUTER JOIN #SchoolsList l
ON n.FILENAME LIKE '%' + l.School + '%'
Riverwood doesn't return a code since you have a space in the school list (SS and NS work since there is actually a space after them in both the filename and the school list)
I think you're looking for
SELECT SL.*
FROM SchoolsList SL JOIN SchoolName SN
ON SN.FileName LIKE CONCAT('%\', RTRIM(LTRIM(SL.School)), '%');
-- You can remove LTRIM() if there is no spaces in the begining
Demo

SQL query to fillter and update table

i have an employee database table with a column NAME
in the NAME field we have names of employees like this -> LI-MING (ALLEN)
this is there real first name and there English nick name in ()
i would like to know if i can swap this around in an SQL UPDATE query
FROM: LI-MING (ALLEN) TO: ALLEN (LI-MING)
the reason why i would like this is Users want to have it sort this column by nick name
Try this
UPDATE Employee
SET NAME =
SUBSTRING(name,CHARINDEX('(',name)+1,(CHARINDEX(')',name)-CHARINDEX('(',name)-1))+
' ('+SUBSTRING(name,1,CHARINDEX('(',name)-1)+')'
FROM Employee
If I were you I would create seperate colums both for name and nick name. Trying to get a string portion on the fly prevent sql server from using indexes which might be really importand from performance perspective.
So there are basicly two options:
Parse values for seperate columns every time you update or insert a new employee (via TRIGGER, application code, etc).
Or just create two calculated columns but make sure they are marked as PERSISTED.
Hope it helps!
I had worked on several project and I have done it my way to update same issue that you been through in 3 steps:
1) Create table with ID or Name field and Insert the values to the table
2) Trim the values with different functions and insert the final value to different table.
3) Update the old table with the new value
I don't say this is the only way to do thing but there might be other ways as well.
Create table #Employee(
EmployeeName varchar(200)
)
Insert into #Employee
Select 'LI-MING (ALLEN)' union all
Select 'Jio-Kio (Smith)'
Select
substring(employeename,1,patindex('%(%',employeename)-1),
--Len(substring(employeename,1,patindex('%(%',employeename)-1)),
Right(employeename,len(employeename)-(len(substring(employeename,1,patindex('%(%',employeename)))))
from #Employee
Create table #EmployeeNew(
Employeename1 varchar(200),
Employeename2 varchar(200)
)
Insert into #EmployeeNew(Employeename1, Employeename2)
Select
ltrim(rtrim(substring(employeename,1,patindex('%(%',employeename)-1))),
ltrim(rtrim(Right(Employeename,charindex('(',employeename,1)-3)))
from #Employee
Select * from #Employee
Select * from #EmployeeNew
Select cast('('+Employeename1+')'+left(employeename2,len(employeename2)-1) as varchar(200)) from #EmployeeNew
Update e
Set e.EmployeeName = cast('('+e1.Employeename1+')'+left(e1.employeename2,len(e1.employeename2)-1) as varchar(200))
from #Employee e
left outer join #EmployeeNew e1 on ltrim(rtrim(substring(e.employeename,1,patindex('%(%',e.employeename)-1))) =e1.Employeename1

How can I compare two name strings that are formatted differently in SQL Server?

What would be the best approach for comparing the following set of strings in SQL Server?
Purpose: The main purpose of this Stored Procedure is to compare a set of input Names of Customers to names that Exist in the Customer database for a specific accounts. If there is a difference between the input name and the name in the Database this should trigger the updating of the Customer Database with the new name information.
Conditions:
Format of Input: FirstName [MiddleName] LastName
Format of Value in Database: LastName, FirstName MiddleName
The complication arises when names like this are presented,
Example:
Input: Dr. John A. Mc Donald
Database: Mc Donald, Dr. John A.
For last names that consist of 2 or more parts what logic would have to be put into place
to ensure that the lastname in the input is being compared to the lastname in the database and likewise for the first name and middle name.
I've thought about breaking the database values up into a temp HASH table since I know that everything before the ',' in the database is the last name. I could then check to see if the input contains the lastname and split out the FirstName [MiddleName] from it to perform another comparison to the database for the values that come after the ','.
There is a second part to this however. In the event that the input name has a completely New last name (i.e. if the name in the database is Mary Smith but the updated input name is now Mary Mc Donald). In this case comparing the database value of the last name before the ',' to the input name will result in no match which is correct, but at this point how does the code know where the last name even begins in the input value? How does it know that her Middle name isn't MC and her last name Donald?
Has anyone had to deal with a similar problem like this before? What solutions did you end up going with?
I greatly appreciate your input and ideas.
Thank you.
Realistically, it's extremely computationally difficult (if not impossible) to know if a name like "Mary Jane Evelyn Scott" is first-middle-last1-last2, first1-first2-middle-last, first1-first2-last1-last2, or some other combination... and that's not even getting into cultural considerations...
So personally, I would suggest a change in the data structure (and, correspondingly, the application's input fields). Instead of a single string for name, break it into several fields, e.g.:
FullName{
title, //i.e. Dr., Professor, etc.
firstName, //or given name
middleName, //doesn't exist in all countries!
lastName, //or surname
qualifiers //i.e. Sr., Jr., fils, D.D.S., PE, Ph.D., etc.
}
Then the user could choose that their first name is "Mary", their middle name is "Jane Evelyn", and their last name is "Scott".
UPDATE
Based on your comments, if you must do this entirely in SQL, I'd do something like the following:
Build a table for all possible combinations of "lastname, firstname [middlename]" given an input string "firstname [middlename] lastname"
Run a query based on the join of your original data and all possible orderings.
So, step 1. would take the string "Dr. John A. Mc Donald" and create the table of values:
'Donald, Dr. John A. Mc'
'Mc Donald, Dr. John A.'
'A. Mc Donald, Dr. John'
'John A. Mc Donald, Dr.'
Then step 2. would search for all occurrences of any of those strings in the database.
Assuming MSSQL 2005 or later, step 1. can be achieved using some recursive CTE, and a modification of a method I've used to split CSV strings (found here) (SQL isn't the ideal language for this form of string manipulation...):
declare #str varchar(200)
set #str = 'Dr. John A. Mc Donald'
--Create a numbers table
select [Number] = identity(int)
into #Numbers
from sysobjects s1
cross join sysobjects s2
create unique clustered index Number_ind on #Numbers(Number) with IGNORE_DUP_KEY
;with nameParts as (
--Split the name string at the spaces.
select [ord] = row_number() over(order by Number),
[part] = substring(fn1, Number, charindex(' ', fn1+' ', Number) - Number)
from (select #str fn1) s
join #Numbers n on substring(' '+fn1, Number, 1) = ' '
where Number<=Len(fn1)+1
),
lastNames as (
--Build all possible lastName strings.
select [firstOrd]=ord, [lastOrd]=ord, [lastName]=cast(part as varchar(max))
from nameParts
where ord!=1 --remove the case where the whole string is the last name
UNION ALL
select firstOrd, p.ord, l.lastName+' '+p.part
from lastNames l
join nameParts p on l.lastOrd+1=p.ord
),
firstNames as (
--Build all possible firstName strings.
select [firstOrd]=ord, [lastOrd]=ord, [firstName]=cast(part as varchar(max))
from nameParts
where ord!=(select max(ord) from nameParts) --remove the case where the whole string is the first name
UNION ALL
select p.ord, f.lastOrd, p.part+' '+f.firstName
from firstNames f
join nameParts p on f.firstOrd-1 = p.ord
)
--Combine for all possible name strings.
select ln.lastName+', '+fn.firstName
from firstNames fn
join lastNames ln on fn.lastOrd+1=ln.firstOrd
where fn.firstOrd=1
and ln.lastOrd = (select max(ord) from nameParts)
drop table #Numbers
Since I had my share of terrible experience with data from third parties, it is almost guaranteed that the input data will contain lots of garbage not following the specified format.
When trying to match data multipart string data like in your case, I preprocessed both input and our data into something I called "normalized string" using the following method.
strip all non-ascii chars (leaving language-specific chars like "č" intact)
compact spaces (replace multiple spaces with single one)
lower case
split into words
remove duplicates
sort alphabetically
join back to string separated by dashes
Using you sample data, this function would produce:
Dr. John A. Mc Donald ->
a-donald-dr-john-mc Mc Donald, Dr.
John A.-> a-donald-dr-john-mc
Unfortunaly it's not 100% bulletproof, there are cases where degenerated inputs produce invalid matches.
Your name field is bad in the database. Redesign and get rid of it. If you havea a first name, middlename, lastname, prefix and suffix sttructure, you can hava computed filed that has the structure you are using. But it is a very poor way to store data and your first priority should be to stop using it.
Since you have a common customer Id why aren't you matching on that instead of name?