I am trying to concatenate the name of the players where some of the players have no middle name. While concatenating as below I am getting an white space for players without a middle name and logic holds good for players with a middle name. How do I remove the unwanted whitespace for NULL valued columns alone?
I want only the Initial of the middle name in the concatenate expression.
SELECT m_playerid, first_name + ' ' + SUBSTRING (coalesce (middle_
name, ' '), 1,1) + ' ' + last_name as [Full name]
, game as Game, inns as Innings, [scores] as Scores FROM odsports
Shouldn't I be introducing a condition to get remove of the
whitespace for NULL? I am struck!
You can use the fact that concatenating a NULL to anything with the + operator produces a NULL whereas the CONCAT function converts NULL to empty string.
So CONCAT(first_name, ' ', LEFT(middle_name,1) + ' ', last_name) will handle null middle names as you want - as in the following example
WITH T(first_name, middle_name, last_name) AS
(
SELECT 'Franklin', 'Delano', 'Roosevelt' union all
SELECT 'Barack', NULL, 'Obama'
)
SELECT CONCAT(first_name, ' ', LEFT(middle_name,1) + ' ', last_name)
FROM T
Returns
+----------------------+
| (No column name) |
+----------------------+
| Franklin D Roosevelt |
| Barack Obama |
+----------------------+
Add a replace for double spaces, as well as use isnull function. Try this
SELECT
m_playerid,
REPLACE(
LTRIM(RTRIM(ISNULL(first_name ,'')))
+CASE WHEN middle_name IS NULL
THEN ' '
ELSE ' '+LEFT(ISNULL(middle_name,' '),1)+' ' END
+
LTRIM(RTRIM(ISNULL(last_name,'')))
,' ',' ') as [Full name],
game as Game,
inns as Innings,
[scores] as Scores
FROM odsports
Try this:
SELECT m_playerid,
COALESCE(first_name + ' ' + middle_name + ' ' + last_name,
first_name + ' ' + last_name,
first_name,
last_name) as [Full name],
game as Game,
inns as Innings,
[scores] as Scores
FROM odsports
SELECT
m_playerid,
LTRIM(CONCAT(first_name,Space(1),LTRIM(RTRIM(middle_name+space(1)+last_name))))
as [Full name],
game as Game,
inns as Innings,
[scores] as Scores
FROM odsports
Related
I need to parse a list of FullNames into First and Last Name. If a middle name is included, it should be included in the fist name field.
John Smith would be:
FirstName = John
LastName = Smith
John J. Smith would be:
FirstName = John J.
LastName = Smith
The issue is the names might be either Thai or English character set. I need to properly parse either set. I have tried just about everything...
DECLARE #FullName NVARCHAR(MAX) = N'กล้วยไม้ สวามิวัศดุ์'
--DECLARE #FullName NVARCHAR(MAX) = N'Mark C. Wilson'
SELECT
LEN(#FullName) AS StringLength,
LEN(#FullName) - LEN(REPLACE(#FullName,N' ', N'')),
LEN(REPLACE(#FullName,N' ', N'')),
#FullName AS FullName,
REVERSE(#FullName) AS ReverseName, -- This is obviously no Reverse of the string
CHARINDEX(N' ', REVERSE(#FullName)) AS LastSpaceLocation,
CHARINDEX(N' ', #FullName) AS FirstSpaceLocation,
LEN(#FullName) AS LenString,
STUFF(#FullName, 1, CHARINDEX(N' ', #FullName), N'') as FirstName,
RIGHT(#FullName, LEN(#FullName) - CHARINDEX(N' ', #FullName) + 1) as LastName,
LEFT(#FullName, LEN(#FullName) - CHARINDEX(N' ', REVERSE(#FullName))) AS FirstName,
STUFF(RIGHT(#FullName, CHARINDEX(N' ', REVERSE(#FullName))),1,1,N'') AS LastName,
LEN(#FullName),
REVERSE(#FullName),
REVERSE(' '),
LEN(#FullName) - CHARINDEX(reverse(' '), REVERSE(#FullName)) - LEN(' ') + 1
The REVERSE simply does not work when the Thai character set is used.
I can't read Thai (I'm not that bright), but perhaps this may help.
Here we are using a CROSS APPLY to "fix" the string, and then it is a small matter of PasrName() and Concat()
I should add, parsing names is a slippery slope. One needs to consider
Multi Word Last Names ie De la Cruz
Suffix ie. Richard R Cappelletti MD
Example
Declare #YourTable table (FullName nvarchar(100))
Insert Into #YourTable values
('John Smith')
,('John J. Smith')
,(N'กล้วยไม้ สวามิวัศดุ์')
Select A.*
,LastName = replace(parsename(S,1),'|','.')
,FirstName = replace(concat(parsename(S,4),' '+parsename(S,3),' '+parsename(S,2)),'|','.')
From #YourTable A
Cross Apply ( values (replace(replace(FullName,'.','|'),' ','.'))) B(S)
Returns
FullName LastName FirstName
John Smith Smith John
John J. Smith Smith John J.
กล้วยไม้ สวามิวัศดุ์ สวามิวัศดุ์ กล้วยไม้
EDIT 2008 Version
Select A.*
,LastName = replace(parsename(S,1),'|','.')
,FirstName = replace( IsNull(parsename(S,4),'') + IsNull(' '+parsename(S,3),'') + IsNull(' '+parsename(S,2),''),'|','.')
From #YourTable A
Cross Apply ( values (replace(replace(FullName,'.','|'),' ','.'))) B(S)
I'm Thai and one thing I know is that Thai people don't do middle name.
set DisplayName = concat(Title, ' ', FirstName, ' ', substring(MiddleName), 0, 2), '. ', LastName, ' ', Suffix)
So, there are names with out a suffix (Title, and names with out the middle name, so no middle initial.
I want it so when it sets Display name, if it has a Tittle and a middle name than provide the space and the period for the middle name. Right now its included null as a blank space, so right now I will get an extra blank space if there is no title,and a period/space if there is no middle initial; I only want it when the values for Middlename and Title are NOT null
This is a standard trick:
SELECT CONCAT(ISNULL('Title' + ' ', ''), 'FirstName', ' ', ISNULL(SUBSTRING('MiddleName', 1, 2) + '. ', ''), 'LastName', ' ', 'Suffix')
SELECT CONCAT(ISNULL(NULL + ' ', ''), 'FirstName', ' ', ISNULL(NULL + '. ', ''), 'LastName', ' ', 'Suffix')
Outputs:
Title FirstName Mi. LastName Suffix
FirstName LastName Suffix
To apply to your example:
SET DisplayName = CONCAT(ISNULL(Title + ' ', ''),
FirstName,
' ',
ISNULL(SUBSTRING(MiddleName, 0, 2) + '. ', ''),
LastName,
' ',
Suffix)
SET displayname = concat(title+' '
, firstname, ' '
, substring(middlename, 0, 2) + '. '
, lastname
, ' ' + suffix)
So what we are doing here is we are using a '+' operator instead of CONCAT. The difference is if a NULL is concatenated using '+' operator it will return a NULL as a result. So if a space will be concatenated with a NULL result, say middle name, the whole thing will become NULL and no blank space will be shown.
If you create DisplayName only for user interface, then I think you can do it in your buisness layer - not sql query
Put all results of sql query in the array or list. Then concatenate only not empty string with empty space between them
For example C# code approach which can be used in others .NET Framework languages
string[] names = {Title, FirstName, MiddleName, LastName, Suffix}
string DisplayName = string.Join(" ", names.Where((value) => String.IsNullOrWhiteSpace(value) == false);
Let's say I have a table like this in SQL Server:
Id City Province Country
1 Vancouver British Columbia Canada
2 New York null null
3 null Adama null
4 null null France
5 Winnepeg Manitoba null
6 null Quebec Canada
7 Seattle null USA
How can I get a query result so that the location is a concatenation of the City, Province, and Country separated by ", ", with nulls omitted. I'd like to ensure that there aren't any trailing comma, preceding commas, or empty strings. For example:
Id Location
1 Vancouver, British Columbia, Canada
2 New York
3 Adama
4 France
5 Winnepeg, Manitoba
6 Quebec, Canada
7 Seattle, USA
I think this takes care of all of the issues I spotted in other answers. No need to test the length of the output or check if the leading character is a comma, no worry about concatenating non-string types, no significant increase in complexity when other columns (e.g. Postal Code) are inevitably added...
DECLARE #x TABLE(Id INT, City VARCHAR(32), Province VARCHAR(32), Country VARCHAR(32));
INSERT #x(Id, City, Province, Country) VALUES
(1,'Vancouver','British Columbia','Canada'),
(2,'New York' , null , null ),
(3, null ,'Adama' , null ),
(4, null , null ,'France'),
(5,'Winnepeg' ,'Manitoba' , null ),
(6, null ,'Quebec' ,'Canada'),
(7,'Seattle' , null ,'USA' );
SELECT Id, Location = STUFF(
COALESCE(', ' + RTRIM(City), '')
+ COALESCE(', ' + RTRIM(Province), '')
+ COALESCE(', ' + RTRIM(Country), '')
, 1, 2, '')
FROM #x;
SQL Server 2012 added a new T-SQL function called CONCAT, but it is not useful here, since you still have to optionally include commas between discovered values, and there is no facility to do that - it just munges values together with no option for a separator. This avoids having to worry about non-string types, but doesn't allow you to handle nulls vs. non-nulls very elegantly.
select Id ,
Coalesce( City + ',' +Province + ',' + Country,
City+ ',' + Province,
Province + ',' + Country,
City+ ',' + Country,
City,
Province,
Country
) as location
from table
This is a hard problem, because the commas have to go in-between:
select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '')
from t
seems like it should work, but we can get an extraneous comma at the end, such as when country is NULL. So, it needs to be a bit more complicated:
select id,
(case when right(val, 2) = ', ' then left(val, len(val) - 1)
else val
end) as val
from (select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '') as val
from t
) t
Without a lot of intermediate logic, I think the simplest way is to add a comma to each element, and then remove any extraneous comma at the end.
Use the '+' operator.
Understand that null values don't work with the '+' operator (so for example: 'Winnepeg' + null = null), so be sure to use the ISNULL() or COALESCE() functions to replace nulls with an empty string, e.g.: ISNULL('Winnepeg','') + ISNULL(null,'').
Also, if it is even remotely possible that one of your collumns could be interpreted as a number, then be sure to use the CAST() function as well, in order to avoid error returns, e.g.: CAST('Winnepeg' as varchar(100)).
Most of the examples so far neglect one or more pieces of this. Also -- some of the examples use subqueries or do a length check, which you really ought not to do -- just not necessary -- though your optimizer might save you anyway if you do.
Good Luck
ugly but it will work for MS SQL:
select
id,
case
when right(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),1)=',' then left(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),LEN(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')))-1)
else rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,''))
end
from
table
I know it's an old question, but should someone should stumble upon this today, SQL Server 2017 and later has the STRING_AGG function, with the WITHIN GROUP option :
with level1 as
(select id,city as varcharColumn,1 as columnRanking from mytable
union
select id,province,2 from mytable
union
select id,country,3 from mytable)
select STRING_AGG(varcharColumn,', ')
within group(order by columnRanking)
from level1
group by id
Should empty strings exist aside of nulls, they should be excluded with some WHERE clause in level1.
Here is an option:
SELECT (CASE WHEN City IS NULL THEN '' ELSE City + ', ' END) +
(CASE WHEN Province IS NULL THEN '' ELSE Province + ', ' END) +
(CASE WHEN Country IS NULL THEN '' ELSE Country END) AS LOCATION
FROM MYTABLE
Is there a method to use contain rather than equal in case statement?
For example, I am checking a database table has an entry
lactulose, Lasix (furosemide), oxazepam, propranolol, rabeprazole, sertraline,
Can I use
CASE When dbo.Table.Column = 'lactulose' Then 'BP Medication' ELSE '' END AS 'BP Medication'
This did not work.
CASE WHEN ', ' + dbo.Table.Column +',' LIKE '%, lactulose,%'
THEN 'BP Medication' ELSE '' END AS [BP Medication]
The leading ', ' and trailing ',' are added so that you can handle the match regardless of where it is in the string (first entry, last entry, or anywhere in between).
That said, why are you storing data you want to search on as a comma-separated string? This violates all kinds of forms and best practices. You should consider normalizing your schema.
In addition: don't use 'single quotes' as identifier delimiters; this syntax is deprecated. Use [square brackets] (preferred) or "double quotes" if you must. See "string literals as column aliases" here: http://msdn.microsoft.com/en-us/library/bb510662%28SQL.100%29.aspx
EDIT If you have multiple values, you can do this (you can't short-hand this with the other CASE syntax variant or by using something like IN()):
CASE
WHEN ', ' + dbo.Table.Column +',' LIKE '%, lactulose,%'
WHEN ', ' + dbo.Table.Column +',' LIKE '%, amlodipine,%'
THEN 'BP Medication' ELSE '' END AS [BP Medication]
If you have more values, it might be worthwhile to use a split function, e.g.
USE tempdb;
GO
CREATE FUNCTION dbo.SplitStrings(#List NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN ( SELECT DISTINCT Item FROM
( SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List,',', '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
CREATE TABLE dbo.[Table](ID INT, [Column] VARCHAR(255));
GO
INSERT dbo.[Table] VALUES
(1,'lactulose, Lasix (furosemide), oxazepam, propranolol, rabeprazole, sertraline,'),
(2,'lactulite, Lasix (furosemide), lactulose, propranolol, rabeprazole, sertraline,'),
(3,'lactulite, Lasix (furosemide), oxazepam, propranolol, rabeprazole, sertraline,'),
(4,'lactulite, Lasix (furosemide), lactulose, amlodipine, rabeprazole, sertraline,');
SELECT t.ID
FROM dbo.[Table] AS t
INNER JOIN dbo.SplitStrings('lactulose,amlodipine') AS s
ON ', ' + t.[Column] + ',' LIKE '%, ' + s.Item + ',%'
GROUP BY t.ID;
GO
Results:
ID
----
1
2
4
Pseudo code, something like:
CASE
When CHARINDEX('lactulose', dbo.Table.Column) > 0 Then 'BP Medication'
ELSE ''
END AS 'Medication Type'
This does not care where the keyword is found in the list and avoids depending on formatting of spaces and commas.
I am creating a computed column across fields of which some are potentially null.
The problem is that if any of those fields is null, the entire computed column will be null. I understand from the Microsoft documentation that this is expected and can be turned off via the setting SET CONCAT_NULL_YIELDS_NULL. However, there I don't want to change this default behavior because I don't know its implications on other parts of SQL Server.
Is there a way for me to just check if a column is null and only append its contents within the computed column formula if its not null?
You can use ISNULL(....)
SET #Concatenated = ISNULL(#Column1, '') + ISNULL(#Column2, '')
If the value of the column/expression is indeed NULL, then the second value specified (here: empty string) will be used instead.
From SQL Server 2012 this is all much easier with the CONCAT function.
It treats NULL as empty string
DECLARE #Column1 VARCHAR(50) = 'Foo',
#Column2 VARCHAR(50) = NULL,
#Column3 VARCHAR(50) = 'Bar';
SELECT CONCAT(#Column1,#Column2,#Column3); /*Returns FooBar*/
Use COALESCE. Instead of your_column use COALESCE(your_column, ''). This will return the empty string instead of NULL.
You can also use CASE - my code below checks for both null values and empty strings, and adds a seperator only if there is a value to follow:
SELECT OrganisationName,
'Address' =
CASE WHEN Addr1 IS NULL OR Addr1 = '' THEN '' ELSE Addr1 END +
CASE WHEN Addr2 IS NULL OR Addr2 = '' THEN '' ELSE ', ' + Addr2 END +
CASE WHEN Addr3 IS NULL OR Addr3 = '' THEN '' ELSE ', ' + Addr3 END +
CASE WHEN County IS NULL OR County = '' THEN '' ELSE ', ' + County END
FROM Organisations
Use
SET CONCAT_NULL_YIELDS_NULL OFF
and concatenation of null values to a string will not result in null.
Please note that this is a deprecated option, avoid using.
See the documentation for more details.
I just wanted to contribute this should someone be looking for help with adding separators between the strings, depending on whether a field is NULL or not.
So in the example of creating a one line address from separate fields
Address1, Address2, Address3, City, PostCode
in my case, I have the following Calculated Column which seems to be working as I want it:
case
when [Address1] IS NOT NULL
then ((( [Address1] +
isnull(', '+[Address2],'')) +
isnull(', '+[Address3],'')) +
isnull(', '+[City] ,'')) +
isnull(', '+[PostCode],'')
end
Hope that helps someone!
ISNULL(ColumnName, '')
I had a lot of trouble with this too. Couldn't get it working using the case examples above, but this does the job for me:
Replace(rtrim(ltrim(ISNULL(Flat_no, '') +
' ' + ISNULL(House_no, '') +
' ' + ISNULL(Street, '') +
' ' + ISNULL(Town, '') +
' ' + ISNULL(City, ''))),' ',' ')
Replace corrects the double spaces caused by concatenating single spaces with nothing between them. r/ltrim gets rid of any spaces at the ends.
In Sql Server:
insert into Table_Name(PersonName,PersonEmail) values(NULL,'xyz#xyz.com')
PersonName is varchar(50), NULL is not a string, because we are not passing with in single codes, so it treat as NULL.
Code Behind:
string name = (txtName.Text=="")? NULL : "'"+ txtName.Text +"'";
string email = txtEmail.Text;
insert into Table_Name(PersonName,PersonEmail) values(name,'"+email+"')
This example will help you to handle various types while creating insert statements
select
'insert into doc(Id, CDate, Str, Code, Price, Tag )' +
'values(' +
'''' + convert(nvarchar(50), Id) + ''',' -- uniqueidentifier
+ '''' + LEFT(CONVERT(VARCHAR, CDate, 120), 10) + ''',' -- date
+ '''' + Str+ ''',' -- string
+ '''' + convert(nvarchar(50), Code) + ''',' -- int
+ convert(nvarchar(50), Price) + ',' -- decimal
+ '''' + ISNULL(Tag, '''''') + '''' + ')' -- nullable string
from doc
where CDate> '2019-01-01 00:00:00.000'