So I have a database of customers. I run SELECT * FROM MyTable it gives me back several columns, one of which is the name. Looks like this:
"Doe, John"
"Jones, Bill"
"Smith, Mike"
"Johnson, Bob"
"Harry Smith"
"Black, Linda"
"White, Laura"
etc. Some are last name, first name. Others are first name last name.
My boss wants me to flip the names so they are all first then last.
So I ran this:
SELECT SUBSTRING(Column_Name, CHARINDEX(',', Column_Name) + 2, LEN(Name) - CHARINDEX(',', Column_Name) + 1) + ' ' + SUBSTRING(Column_Name, 1, CHARINDEX(',', Column_Name) - 1) FROM MyTable
The problem is that when I run that, it only runs the names until it finds one it doesn't need to flip. So in the example above, it would only give me the first four names, not all of them.
It was suggested to me that I could use the PATINDEX() to pull out all of the names. I don't know how to use this and was hoping I could get some help with it.
I suspect your code has TRY/CATCH or you are otherwise swallowing/suppressing/ignoring errors. You should get 4 rows back and then a big ugly error message:
Msg 537, Level 16, State 2
Invalid length parameter passed to the LEFT or SUBSTRING function.
The problem is that your expression assumes that , always exists. You need to cater for that either by filtering out the rows that don't contain a , (though this is not very dependable, since the expression could be attempted before the filter), or the following way, where you make different decisions about how to reassemble the string based on whether a , is found or not:
DECLARE #x TABLE(y VARCHAR(255));
INSERT #x VALUES
('Doe, John'),
('Jones, Bill'),
('Smith, Mike'),
('Johnson, Bob'),
('Harry Smith'),
('Black, Linda'),
('White, Laura');
SELECT LTRIM(SUBSTRING(y, COALESCE(NULLIF(CHARINDEX(',',y)+2,2),1),255))
+ RTRIM(' ' + LEFT(y, COALESCE(NULLIF(CHARINDEX(',' ,y)-1,-1),0)))
FROM #x;
Results:
John Doe
Bill Jones
Mike Smith
Bob Johnson
Harry Smith
Linda Black
Laura White
You don't need PATINDEX in this case, although it could be used. I'd take your expression to flip the names and put it in a CASE expression.
DECLARE #MyTable TABLE
(
Name VARCHAR(64) NOT NULL
);
INSERT #MyTable(Name)
VALUES
('Doe, John'),
('Jones, Bill'),
('Smith, Mike'),
('Johnson, Bob'),
('Harry Smith'),
('Black, Linda'),
('White, Laura');
SELECT
CASE
WHEN CHARINDEX(',', Name, 1) = 0 THEN Name
ELSE SUBSTRING(Name, CHARINDEX(',', Name) + 2, LEN(Name) - CHARINDEX(',', Name) + 1)
+ ' ' + SUBSTRING(Name, 1, CHARINDEX(',', Name) - 1)
END AS [Name]
FROM #MyTable;
The first condition simply returns the original value if no comma was used.
Related
Using SQL Server Azure or 2017 with Full Text Search, I need to return possible matches on names.
Here's the simple scenario: an administrator is entering contact information for a new employee, first name, last name, address, etc. I want to be able to search the Employee table for a possible match on the name(s) to see if this employee has already been entered in the database.
This might happen as an autosuggest type of feature, or simply display some similar results, like here in Stackoverflow, while the admin is entering the data.
I need to prevent duplicates!
If the admin enters "Bob", "Johnson", I want to be able to match on:
Bob Johnson
Rob Johnson
Robert Johnson
This will give the administrator the option of seeing if this person has already been entered into the database and choose one of those choices.
Is it possible to do this type of match on words like "Bob" and include "Robert" in the results? If so, what is necessary to accomplish this?
Try this.
You need to change the #per parameter value to your requirement. It indicates how many letters out of the length of the first name should match for the result to return. I just set it to 50% for testing purposes.
The dynamic SQL piece inside the loop adds all the CHARINDEX result per letter of the first name in question, to all existing first names.
Caveats:
Repeating letters will of course be misleading, like Bob will count 3 matches in Rob because there's 2 Bs in Bob.
I didn't consider 2 first names, like Bob Robert Johnson, etc so this will fail. You can improve on that however, but you get the idea.
The final SQL query gets the LetterMatch that is greater than or equal to the set value in #per.
DECLARE #name varchar(MAX) = 'Bobby Johnson' --sample name
DECLARE #first varchar(50) = SUBSTRING(#name, 0, CHARINDEX(' ', #name)) --get the first part of the name before space
DECLARE #last varchar(50) = SUBSTRING(#name, CHARINDEX(' ', #name) + 1, LEN(#name) - LEN(#first) - 1) --get the last part of the name after space
DECLARE #walker int = 1 --for looping
DECLARE #per float = LEN(#first) * 0.50 --declare percentage of how many letters out of the length of the first name should match. I just used 50% for testing
DECLARE #char char --for looping
DECLARE #sql varchar(MAX) --for dynamic SQL use
DECLARE #matcher varchar(MAX) = '' --for dynamic SQL use
WHILE #walker <> LEN(#first) + 1 BEGIN --loop through all the letters of the first name saved in #first variable
SET #char = SUBSTRING(#first, #walker, 1) --save the current letter in the iteration
SET #matcher = #matcher + IIF(#matcher = '', '', ' + ') + 'IIF(CHARINDEX(''' + #char + ''', FirstName) > 0, 1, 0)' --build the additional column to be added to the dynamic SQL
SET #walker = #walker + 1 --move the loop
END
SET #sql = 'SELECT * FROM (SELECT FirstName, LastName, ' + #matcher + ' AS LetterMatch
FROM TestName
WHERE LastName LIKE ' + '''%' + #last + '%''' + ') AS src
WHERE CAST(LetterMatch AS int) >= ROUND(' + CAST(#per AS varchar(50)) + ', 0)'
SELECT #sql
EXEC(#sql)
SELECT * FROM tbl_Names
WHERE Name LIKE '% user defined text %';
using a text in between % % will search those text on any position in the data.
I have a field with names in the format DOE JOHN HOWARD or DOE JOHN H.
I need a query to get the string between the two spaces (JOHN in this case).
The SO answer here shows how to do that when the desired substring is between two different strings, but I don't see how to apply something similar when the desired substring is between two instances of the same string (a space in this case).
How can I do that?
There is a somewhat sneaky way you could do this using PARSENAME.
It's intended purpose is to get particular parts of an object/namespace, however, in this case you could use it by replacing the strings with periods first.
E.g.,
SELECT PARSENAME(REPLACE('DOE JOHN HOWARD',' ','.'),2)
One way:
select
left(substring(fld,
charindex(' ', fld) + 1, len(fld)),
charindex(' ', substring(fld, charindex(' ', fld) + 2, len(fld))))
After doing some searches to resolve my problem, realised there is no generic answer, so below is piece of code to find string between some other strings. I think it may be useful for somebody in future.
DECLARE #STRING NVARCHAR(MAX) = 'Something here then stringBefore Searching stringAfter something there.'
DECLARE #FIRST NVARCHAR(20) = 'stringBefore'
DECLARE #SECOND NVARCHAR(20) = 'stringAfter'
DECLARE #SEARCHING NVARCHAR (20)
SET #SEARCHING = (SELECT SUBSTRING(#STRING, CHARINDEX(#FIRST, #STRING) + LEN(#FIRST), CHARINDEX(#SECOND, #STRING) - CHARINDEX(#FIRST, #STRING) - LEN(#FIRST)))
-- if you want to remove empty spaces
SET #SEARCHING = REPLACE(#SEARCHING, ' ', '')
SELECT #SEARCHING
Then output as below:
(No column name)
Searching
I know to do parts of it but not all of it, lets say my table name is REV and column name is DESCR and it has a value like
R&B , Semiprivate 2 Beds , Medical/Surgical/GYN
i use
SELECT DESCR, LEFT(DESCR, Charindex(',', DESCR)), SUBSTRING(DESCR, CHARINDEX(',', DESCR) + 1, LEN(DESCR)) from REV
i get 'R&B ,' in one column and 'Semiprivate 2 Beds , Medical/Surgical/GYN' in another column in the above select statement but i dont know how to selesct the strings from teh second comma onwards
what i like to return is 'R&B' in one column without the comma and 'Semiprivate 2 Beds' in another column and 'Medical/Surgical/GYN' so on
basically select test between commas and when there is no comma it should be blank
This should work:
SELECT
LEFT(DESCR, CHARINDEX(',', DESCR)-1),
SUBSTRING(DESCR, CHARINDEX(',', DESCR)+1, CHARINDEX(',', DESCR, CHARINDEX(',', DESCR)+1) - CHARINDEX(',', DESCR) -1 ),
RIGHT(DESCR, CHARINDEX(',', REVERSE(DESCR))-1)
FROM REV
This should work:
SELECT
LEFT(DESCR, CHARINDEX(',', DESCR)-1),
SUBSTRING(DESCR, CHARINDEX(',', DESCR)+1, LEN(DESCR)-CHARINDEX(',', DESCR)-CHARINDEX(',',REVERSE(DESCR ))),
RIGHT(DESCR, CHARINDEX(',', REVERSE(DESCR))-1)
FROM REV
Sample SQL Fiddle
This will split the string, but leave blank at the beginning and end of the strings, you can use LTRIMand RTRIMto trim away the blanks.
There might be better ways to do this though; see the article Split strings the right way – or the next best way by Aaron Bertrand at (that Andrew mentioned in a comment).
I have an MSSQL database field that looks like the examples below:
u129 james
u300 chris
u300a jim
u202 jane
u5 brian
u5z brian2
Is there a way to select the first set of characters? Basically select all the characters up until the first line space?
I tried messing around with LEFT, RIGHT, LEN, but couldn't figure out a way to do it with variable string lengths like in my example.
Thanks!
You can use a combiation of LEFT and CHARINDEX to find the index of the first space, and then grab everything to the left of that.
SELECT LEFT(YourColumn, charindex(' ', YourColumn) - 1)
And in case any of your columns don't have a space in them:
SELECT LEFT(YourColumn, CASE WHEN charindex(' ', YourColumn) = 0 THEN
LEN(YourColumn) ELSE charindex(' ', YourColumn) - 1 END)
select left(col, charindex(' ', col) - 1)
If the first column is always the same size (including the spaces), then you can just take those characters (via LEFT) and clean up the spaces (with RTRIM):
SELECT RTRIM(LEFT(YourColumn, YourColumnSize))
Alternatively, you can extract the second (or third, etc.) column (using SUBSTRING):
SELECT RTRIM(SUBSTRING(YourColumn, PreviousColumnSizes, YourColumnSize))
One benefit of this approach (especially if YourColumn is the result of a computation) is that YourColumn is only specified once.
An alternative if you sometimes do not have spaces do not want to use the CASE statement
select REVERSE(RIGHT(REVERSE(YourColumn), LEN(YourColumn) - CHARINDEX(' ', REVERSE(YourColumn))))
This works in SQL Server, and according to my searching MySQL has the same functions
If space is missing, you can add one
SELECT LEFT('YourTextOrColumn',
charindex(' ',
'YourTextOrColumn' + ' ') - 1 )
I have a employee table and the sample data in it is like this. I am using sql server 2008.
CREATE TABLE employee (name nvarchar(255))
insert into employee (name) values ('Alex,AlexMartin'),
('John,John'),
('Mayr,Mayr'),
('Shel,Sheila'),
('corolla,corolla,corolla3'),
('Mary4,Mary,Mary'),
('Justin,Justin,Justin'),
('Sara,Sara,Sara,Sara'),
('clarence,clarence,clarence458,clarence,clarence'),
('fiesta,fiesta,fiesta,fiesta,fiesta'),
('scorpio1,scorpio,scorpio,scorpio4,scorpio')
I want to delete a value if all the values in the string are same example: John,John should be replaced by 'John'. If all the names in string are not equal like Shel,Sheila it should retain both the values.
For this I am using
update employee set name=(select PARSENAME(REPLACE(name, ',', '.'), 2)) where (select PARSENAME(REPLACE(name, ',', '.'), 2))
like (select PARSENAME(REPLACE(name, ',', '.'), 1)) but it is changing Mary4,Mary,Mary to Mary. I tried combinations for 5, 4, and 3 names but there is no use. In fact for five names this code is not at all working. Is there any efficient way to do this?
This will get the data in the format you're looking for:
CREATE TABLE #Employee (Name NVarChar(255));
INSERT INTO #Employee (Name) VALUES ('Alex,AlexMartin'),
('John,John'),
('Mayr,Mayr'),
('Shel,Sheila'),
('corolla,corolla,corolla3'),
('Mary4,Mary,Mary'),
('Justin,Justin,Justin'),
('Sara,Sara,Sara,Sara'),
('clarence,clarence,clarence458,clarence,clarence'),
('fiesta,fiesta,fiesta,fiesta,fiesta'),
('scorpio1,scorpio,scorpio,scorpio4,scorpio'),
('Another');
SELECT Name, CASE
WHEN CHARINDEX(Name, ',') = 0 THEN Name
WHEN
REPLACE(REPLACE(Name, LEFT(Name, CHARINDEX(',', Name) - 1), ''), ',', '') = ''
THEN LEFT(Name, CHARINDEX(',', Name) - 1)
ELSE Name
END Result
FROM #Employee;
DROP TABLE #Employee;
It works by getting the first name in the comma-separated list. By your requirements all of the items have to be identical in order to condense the list, so it doesn't matter which element in the list we use for comparison.
All occurrences of the first item are removed from the list. Then all of the commas are removed. If the resulting value is empty (i.e. '') then we know all of the items are identical. In that case the first element is used as the Result value. Otherwise, we return the original list unchanged.
EDIT: Some of your data mustn't have a , in it, so I've updated the answer to take care of that. It will just return the same input if a delimiter doesn't exist.