simplifying a LEFT / REPLACE query - sql

I have a query that is in dire need of being simplified. Here is part of the query:
SELECT
LEFT(MLIS.REQUESTOR_FIRST_NAME, CharIndex( ' ', MLIS.REQUESTOR_FIRST_NAME + ' ' ) - 1)
, CharIndex( ' ', LEFT(MLIS.REQUESTOR_FIRST_NAME, CharIndex( ' ', MLIS.REQUESTOR_FIRST_NAME + ' ' ) - 1) + ' ' ) - 1)
+REPLICATE(' ',25),25)+
LEFT(' '+REPLICATE(' ',20),20)+
LEFT(
LEFT(
LEFT(MLIS.REQUESTOR_LAST_NAME, CharIndex( ',', MLIS.REQUESTOR_LAST_NAME + ',' ) - 1)
, CharIndex( ',', LEFT(MLIS.REQUESTOR_LAST_NAME, CharIndex( ',', MLIS.REQUESTOR_LAST_NAME + ',' ) - 1) + ',' ) - 1)
the reason I am doing the replicates is because i am building a fixed length string. each column needs to be a fixed length.
in addition to the above query, for every occurrence of MLIS.REQUESTOR_FIRST_NAME and MLIS.REQUESTOR_LAST_NAME i need to do:
REPLACE(REPLACE(MLIS.REQUESTOR_FIRST_NAME,', MD',''),',MD','')
and
REPLACE(REPLACE(MLIS.REQUESTOR_LAST_NAME,', MD',''),',MD','')
How do I include these REPLACES in the query and simplify the entire thing?
thanks so much for your guidance and kind help.

select the common bits in a subquery... (you'll have a bit more)
SELECT
LEFT(REQUESTOR_FIRST_NAME, fname_idx - 1)
, CharIndex( ' ', LEFT(MLIS.REQUESTOR_FIRST_NAME, fname_idx - 1) + ' ' ) - 1)
..
FROM ( select CharIndex( ' ', MLIS.REQUESTOR_FIRST_NAME + ' ' ) fname_idx, REQUESTOR_FIRST_NAME from...

Using a subquery will help with the syntax. In addition, you can cast to a CHAR() to pad and truncate strings to a given length.
I think the following does what you want:
SELECT cast(fname as char(25)) + ' ' + cast(lname as char(25))
from (select replace(replace(LEFT(MLIS.REQUESTOR_FIRST_NAME,
CharIndex(' ', MLIS.REQUESTOR_FIRST_NAME + ' ' ) - 1
),
',MD', ''),
', MD', '') as fname,
replace(relpace(left(MLIS.REQUESTOR_LAST_NAME,
CharIndex(',', MLIS.REQUESTOR_LAST_NAME + ',' ) - 1),
CharIndex(',', LEFT(MLIS.REQUESTOR_LAST_NAME,
CharIndex( ',', MLIS.REQUESTOR_LAST_NAME + ',' ) - 1) + ','
) - 1
),
',MD', ''),
', MD', '') as lname
However, it is hard to follow the original query, and there might be a syntax error. This query is meant to give you some guidance on solving the problem. I would also put a cast after the concatenate to be sure the final string is the right length.

Related

I'm having trouble separating the first name from the middle name column in SQL Server 2017

I created this syntax to separate first name, middle name and last name from a column called invertornames. Just to note that the investor names are in arabic and their middle names are more than 3 words. It worked fine but the first name is also being included in the middle name as you can see below in the image
This is the query I wrote:
SELECT
SUBSTRING(investor_name, CHARINDEX(', ', investor_name) + 2, CASE WHEN CHARINDEX(' ', investor_name, CHARINDEX(', ', investor_name) + 2) = 0 THEN LEN(investor_name) + 1 ELSE CHARINDEX(' ', investor_name, CHARINDEX(', ', investor_name) + 2) END - CHARINDEX(', ', investor_name) - 2)AS FirstName,
RTRIM(LTRIM(REPLACE(REPLACE(investor_name,SUBSTRING(investor_name , 1, CHARINDEX(' ', investor_name) -1),''),REVERSE( LEFT( REVERSE(investor_name), CHARINDEX(' ', REVERSE(investor_name))-1 ) ),''))) AS MiddleName,
RIGHT(investor_name, CHARINDEX(' ', REVERSE(investor_name))) AS LastName
FROM
investornames
If you need any data to try it please let me know.
You may try this. I consider that First word is considered as Firstname, second word is considered as MiddleName and remaining word will considered as LastName.
For the case of arabic names. Software will not automatically detect that for which name calculation start from the front and for which it is taken in reverse. So I guess you need to maintain a flag for same.
In case of arabic name in the portion of cte use reverse to arrange them in left to right order instead of right to left order. And at the end use reverse function again to convert them into their original state.
Hope I am clear about what I am explaining. Sample code is following :-
; with cte as (
select 'Deepak kumar singh' as names
union
select 'Deep'
union
select 'deep kumar'
union
select 'Deepak kumar singh chandel')
SELECT
Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 1)) As [FirstName]
, Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) As [MiddleName]
, case when len( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 3)))>0 then substring ( names ,
charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ') + 1
, len(names) - charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ')) else null end
As [LastName]
FROM (Select names from cte ) As [x]
Result of above query is:
FirstName MiddleName LastName
Deep NULL NULL
deep kumar NULL
Deepak kumar singh
deepak kumar singh chandel
Edit
Updated this ans check this
; with cte as (
select ' شركة عبدالمحسن عبدالعزيزالبابطين ' as names
union
select 'شركة'
union
select 'عبدالمحسن عبدالعزيز'
union
select 'البابطين')
, ct as (
select RTRIM(LTRIM(names)) as Names from cte )
SELECT
Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 1)) As [FirstName]
, Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) As [MiddleName]
, case when len( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 3)))>0 then substring ( names ,
charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ') + 1
, len(names) - charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ')) else null end
As [LastName]
FROM (Select names from ct ) As [x]
Result
FirstName MiddleName LastName
???? ????????? ?????????????????
???? NULL NULL
???????? NULL NULL
????????? ????????? NULL
Here I am expecting on place of ? you'll get your result. BTW I've updated my query, have you tried this one. Just give one more try.

Trim extra white space within column

I have the following select that is converting a name from Lastname, Firstname format into Firstname Lastname format. It seems to be adding extra white space between the first name and the last name
SELECT substring(D.NAME, charindex(',', replace(D.NAME, ' ', '')) + 1, len(D.NAME))
+ ' '
+ left(D.NAME, charindex(',', D.NAME) -1) AS First_Last
FROM TEST_TABLE D
Here are a few examples of the output I'm getting now:
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
Desired Format (single space between first and last name):
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
I tend to like this technique. In this example we use a rare replacement pattern of †‡, but you can use <> and ><
Note: The outer ltrim(rtrim( ... )) is optional, I keep it as a "just in case".
Example
Select NewValue = ltrim(rtrim(replace(replace(replace([Name],' ','†‡'),'‡†',''),'†‡',' ')))
From YourTable
Returns
NewValue
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
Maybe there are names with or without , or with or without spaces after the ,, or other inconsistencies.
Anyway you can use ltrim(rtrim()) before concatenating:
select
case
when d.name like '%,%' then
ltrim(rtrim(substring(d.name, charindex(',', name) + 1, len(d.name))))
+ ' ' +
ltrim(rtrim(left(D.NAME, charindex(',', d.name) -1)))
when d.name like '% %' then
ltrim(rtrim(substring(d.name, charindex(' ', name) + 1, len(d.name))))
+ ' ' +
ltrim(rtrim(left(D.NAME, charindex(' ', d.name) -1)))
else ltrim(rtrim(d.name))
end AS First_Last
Try:
select ltrim(rtrim(left(D.NAME, charindex(',', D.NAME, 0) - 1)))
+ ' '
+ ltrim(rtrim(right(D.NAME, len(D.NAME) - charindex(',', D.NAME, 0))))
from TEST_TABLE D
This worked on some test data I used below:
insert into #Test ([Name]) values ('Johnnyyy, Smithsonnn')
insert into #Test ([Name]) values ('Kimmey, Test1')
insert into #Test ([Name]) values ('Denise, Stuffing')
Which gives the intended result:
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
I think you intend to do the replace of spaces after extracting the name. So:
SELECT (replace(left(D.NAME, charindex(',', D.NAME + ',') + 1), ' ', '') +
' ' +
left(D.NAME, charindex(',', D.NAME + ',') - 1)
) AS First_Last
FROM TEST_TABLE D;
This also adds a comma for the charindex() so the comma is optional.

Remove all instances of specific value from comma separated string

I want to remove a given value (e.g. 1) from the following string without splitting or using XML functionality.
/* input: */ #ObjectValue = '1,121,4,5,1,111,131,1'
/* output: */ '121,4,5,111,131'
I think the simplest method is:
SELECT TRIM(',' from REPLACE(',' + #ObjectValue + ',', ',1,', ','))
TRIM() is not available in older versions of SQL Server. One method is to replace the commas with spaces and using the available trim functions:
SELECT REPLACE(LTRIM(RTRIM(REPLACE(REPLACE(',' + #ObjectValue + ',', ',1,', ','), ',', ' '))), ' ', ','),
You need to double the delimiters in the list so that 1,1,1 becomes ,1,,1,,1,. Then replace all ,1, and cleanup afterwards:
SELECT ObjectValue, REPLACE(
LTRIM(RTRIM(
REPLACE(' ' + REPLACE(ObjectValue, ',', ' ') + ' ', ' 1 ', '')
)), ' ', ','
)
FROM (VALUES
('1'),
('1,1'),
('1,1,1'),
('0,1,0'),
('0,1,1,0'),
('0,1,1,1,0'),
('0,1,0,1,0'),
('1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,1')
) AS v(ObjectValue)
-- SSMS 2017
DECLARE #ObjectValue VARCHAR(100) = '1,121,4,5,1,111,131,1'
SELECT TRIM(',' FROM REPLACE(REPLACE(',' + #ObjectValue + ',', ',1,', ','),',1,', ','))
-- SSMS 2016 or earlier
DECLARE #Replacetxt VARCHAR(MAX)
SET #ObjectValue=REPLACE(REPLACE(','+#ObjectValue+',', ',1,', ','), ',1,', ',') --Replace ',1,' with ','
SET #Replacetxt=REVERSE(SUBSTRING(#ObjectValue, PATINDEX('%[^,]%', #ObjectValue), LEN(#ObjectValue))) -- Remove comma from starting and reverse string
SELECT REVERSE(SUBSTRING(#Replacetxt, PATINDEX('%[^,]%', #Replacetxt), LEN(#ObjectValue))) -- Remove comma from ending and reverse string

comma separated column values

I need to take the values from 3 columns and group them into 1 column as comma separated:
2014-01-01,2014-01-29
The problem is that one or more columns can be NULL and therefore it messes up the commas as such:
2014-01-01,,2014-01-29
This is how I have it coded (the case statement basically just strips out a comma if it's the last character in the string.
I need to add some logic so that it takes into account NULLs but I'm having a hard time coming up with it.
CASE WHEN RIGHT(ISNULL(d.FirstGapDate + ',', '') + ISNULL(d.PayrollGapDate + ',', '') + d.LastGapDate, 1) = ','
THEN LEFT(ISNULL(d.FirstGapDate + ',', '') + ISNULL(d.PayrollGapDate + ',', '') + d.LastGapDate, LEN(ISNULL(d.FirstGapDate + ',', '') + ISNULL(d.PayrollGapDate + ',', '') + d.LastGapDate) - 1)
ELSE ISNULL(d.FirstGapDate + ',', '') + ISNULL(d.PayrollGapDate + ',', '') + d.LastGapDate
END AS AlLGapDatesFormatted
EDIT -
I need to group the highlighted (notice that PayrollGapDate is ''):
And this is what I'm getting:
And this is the code I implemented:
try using this technique:
SET CONCAT_NULL_YIELDS_NULL ON --<<<make sure concatenations with NULL result in NULL
DECLARE #C1 varchar(10)='AAA'
,#C2 varchar(10)='BBB'
,#C3 varchar(10)=null
,#C4 varchar(10)='DDD'
SELECT STUFF( ISNULL(', '+#C1,'')
+ISNULL(', '+#C2,'')
+ISNULL(', '+#C3,'')
+ISNULL(', '+#C4,'')
,1,2,''
)
output:
-----------------------------------------------
AAA, BBB, DDD
(1 row(s) affected)
You let the ', '+#C3 result in NULL, which the ISNULL(***,'') converts to empty string. The STUFF(***,1,2,'') removes the leading comma and space.
try:
SELECT STUFF( ISNULL(', '+d.FirstGapDate,'')
+ISNULL(', '+d.PayrollGapDate,'')
+ISNULL(', '+d.LastGapDate,'')
,1,2,''
)
FROM ...
WHERE...
You can apply something like this above your expression to replace many commas with one comma:
declare #s varchar(100) = 'ABC,,,,DEF'
select replace(replace(replace(#s, ',', '[]'), '][', ''), '[]', ',')

What's the shortest TSQL to concatenate a person's name which may contain nulls

3 fields: FirstName, MiddleName, LastName
Any field can be null, but I don't want extra spaces. Format should be "First Middle Last", "First Last", "Last", etc.
LTRIM(RTRIM(
LTRIM(RTRIM(ISNULL(FirstName, ''))) + ' ' +
LTRIM(RTRIM(ISNULL(MiddleName, ''))) + ' ' +
LTRIM(ISNULL(LastName, ''))
))
NOTE: This won't leave trailing or leading spaces. That's why it's a little bit uglier than other solutions.
Assuming by "extra spaces", you mean extra spaces inserted during the concatenation (which is a reasonable assumption, I think. If you have extra spaces in your data, you should clean it up):
ISNULL(FirstName + ' ', '') + ISNULL(MiddleName + ' ', '') + ISNULL(LastName, '')
works, since you'll add a space to the name - which if it's NULL yields NULL - which yields empty string.
Edit: If you don't count the SET OPTION - which can be a connection or db option:
SET CONCAT_NULL_YIELDS_NULL OFF
LTRIM(FirstName + ' ' + NULLIF(MiddleName + ' ', ' ') + LastName)
is a tiny bit shorter, but a large bit uglier.
Edit2: Since you accepted the UDF answer - IMO, that's a bit of a cheat - here's some in the same vein:
SELECT a FROM b
b is a view. ;) Or. a stored proc,
EXEC c
But, since EXEC is optional:
c
use a UDF:
`Select udfConcatName(First, Middle, Last) from foo`
That way all your logic for concatenating names is in one place and once you've gotten it written it's short to call.
LTRIM(RTRIM(ISNULL(FirstName, '') + ' ' + LTRIM(ISNULL(MiddleName, '') + ' ' +
ISNULL(LastName, ''))))
Why not use a computed column on the table that performs the concat for you using your preferred syntax from the many posted here? Then you will just query the computed column - very elegant and if you persist the computed column then you may even get slight performance increase.
Example here
replace(ltrim(rtrim(isnull(FirstName, '') + ' ' + isnull(MiddleName, '') + ' ' + isnull(LastName, ''))), ' ', ' ')
'"' + ltrim(rtrim(isnull(FirstName,''))) + ' ' + ltrim(rtrim(isnull(MiddleName,''))) +
' ' + ltrim(rtrim(isnull(LastName,''))) + '","' + ltrim(rtrim(isnull(FirstName,''))) +
' ' + ltrim(rtrim(isnull(LastName,''))) + '","' + ltrim(rtrim(isnull(LastName,''))) +
'"'
ETC
DECLARE #first varchar(10) = 'First'
DECLARE #middle varchar(10) = ''
DECLARE #last varchar(10) = 'Last'
LTRIM(RTRIM(
#first
+ ISNULL(NULLIF(' '+LTRIM(RTRIM(#middle)),' '),'')
+ ISNULL(NULLIF(' '+LTRIM(RTRIM(#last)),' '),'')
))
WHY THIS WORKS
The fields are reduced to an empty string if NULL or whitespace by the LTRIM, RTRIM, and ISNULL functions.
LTRIM(RTRIM(ISNULL(#middle,''))) -- Result is a trimmed non-null string value.
That value is prefixed with a single space, then compared to a single space by the NULLIF function. If equal, a NULL results. If not equal, then the value is used.
NULLIF(' '+'',' ') -- this would return NULL
NULLIF(' '+'Smith',' ') -- this would return ' Smith'
Finally, ISNULL() is used to convert the NULL passed by NULLIF to an empty string.
ISNULL(NULL,'') -- this would return ''
ISNULL(' Smith','') -- this would return ' Smith'
LTrim(RTrim(Replace(IsNull(Firstname + ' ', '') +
isNull(MiddleName, '') +
IsNull(' ' + LastName, ''), ' ', ' ')))
Select firstname, middlename, lastname, ProvidedName =
RTrim(Coalesce(FirstName + ' ','')
+ Coalesce(MiddleName + ' ', '')
+ Coalesce(LastName + ' ', '')
+ COALESCE('' + ' ', '')
+ COALESCE(NULL, ''))
From names