Concatenate first name, last name and middle name with comma - sql

I want to concatenate 3 columns in SQL server as below:
MAX(LTRIM(RTRIM((ISNULL(LastName,'') +
', ' +
ISNULL(FirstName,'') +
', ' +
ISNULL(MiddleName,''))))) AS FullName
I have used value of this column in SELECT clause as:
MAX(FullName) AS FullName,
I would like to handle NULL values, in case all 3 last name, middle name and first name are BLANK or NULL. The query used above will show " , , " in case all 3 columns are NULL or BLANK. But I want to show "N/A" in such case.
Thanks in advance.

You could use a CASE expression:
SELECT MAX(CASE WHEN ISNULL(FirstName, '') = '' AND
ISNULL(MiddleName, '') = '' AND
ISNULL(LastName, '') = ''
THEN 'N/A'
ELSE LTRIM(RTRIM((ISNULL(LastName,'') + ', ' +
ISNULL(FirstName,'') + ', ' +
ISNULL(MiddleName,''))))
END) AS FullName
FROM yourTable
...

Check with COALESCE and then CASE Statement:
Declare #FirstName VARCHAR(50)='',#MiddleName VARCHAR(50),#LastName VARCHAR(50)
SELECT
CASE WHEN ISNULL(COALESCE(#FirstName,#MiddleName,#LastName),'')<>''
THEN ISNULL(#FirstName,'')+',' +ISNULL(#MiddleName,'')+','+ISNULL(#LastName,'')
ELSE 'N/A' END AS FullName

Use Concat like below this will do implicit conversion. So no need to use ISNULL.
select isnull(MAX(LTRIM(RTRIM((concat(LastName,
', ' ,
FirstName,
', ' ,
MiddleName,''))))) ,'n/a')AS FullName from table

The below method may seem quite complicated, but it does make adding or removing columns much simpler, and for all its perceived complexity it isn't actually doing that much under the hood, so doesn't add much overhead.
The first step is to unpivot each of your columns to rows with a common column name, so you would turn
FirstName MiddleName LastName
------------------------------------
A NULL C
Into
Name
------
A
NULL
C
Using CROSS APPLY along with the table value constructor VALUES
SELECT x.Name
FROM (VALUES ('A', NULL,'C')) AS t (FirstName, MiddleName, LastName)
CROSS APPLY (VALUES (1, t.FirstName), (2, t.MiddleName), (3, t.LastName)) x (SortOrder, Name)
ORDER BY x.SortOrder
Then you can remove NULLs and blanks with WHERE ISNULL(Name, '') <> '', then you only have valid data to concatenate together which you can do using SQL Server's XML Extensions. So you end up with a full query like:
WITH TestData AS
( SELECT *
FROM (VALUES ('A'), (NULL)) AS f (FirstName)
CROSS JOIN (VALUES ('B'), (NULL)) AS m (MiddleName)
CROSS JOIN (VALUES ('C'), (NULL)) AS l (LastName)
)
SELECT t.*,
NamesConcat = ISNULL(STUFF(NamesConcat.value('.', 'NVARCHAR(MAX)'), 1, 2, ''), 'N/A')
FROM TestData AS t
CROSS APPLY
( SELECT ', ' + x.Name
FROM (VALUES
(1, t.FirstName),
(2, t.MiddleName),
(3, t.LastName)
) x (SortOrder, Name)
WHERE ISNULL(x.Name, '') <> '' -- NOT BLANK OR NULL
ORDER BY x.SortOrder
FOR XML PATH(''), TYPE
) x (NamesConcat);
Result
FirstName MiddleName LastName NamesConcat
-------------------------------------------------
A B C A, B, C
A NULL C A, C
A B NULL A, B
A NULL NULL A
NULL B C B, C
NULL NULL C C
NULL B NULL B
NULL NULL NULL N/A

select Isnull(FirstName,' ') +' '+ ','+ Isnull(MiddleName,' ')+' '+ ' ,'+ Isnull(Lastname,' ') as Name from personaldata
select FirstName +' '+','+ MiddleName +' '+',' + Lastname as Name from personaldata
Note: The Second query will work fine if all value present and if anyone is null then it will return null for Name, to avoid such kind of concern please use the first query.

Related

One column into multiple columns by type, plus concatenating multiples

I have a table like this:
Customer
Number
Type
1
234.567.8910
1
1
234.234.2345
2
2
234.567.5555
1
2
151.513.5464
1
3
845.846.8486
3
I am trying to include this information with information from another table (say... address), but in separate columns by type, and I want to concatenate values that are of the same type so that the return looks like this:
Customer
Cell
Home
Work
1
234.567.8910
234.234.2345
NULL
2
234.567.5555 & 151.513.5464
NULL
NULL
3
NULL
NULL
845.846.8486
When I use the STRING_AGG function, it appends the value for each line of that customer - even if it would be null when the function isn't applied, so the customer 1 has both the cell and home numbers repeated twice.
The only workaround I can find is to select each column in a subquery and join them together. Is that the only option?
Try with FOR XML and PATH.
Query
select [Customer],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 1
for xml path (''))
, 1, 1, '') as [Cell],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 2
for xml path (''))
, 1, 1, '') as [Home],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 3
for xml path (''))
, 1, 1, '') as [Work]
from [your_table_name] as a
group by [Customer];
You need conditional aggregation:
SELECT
Customer,
STRING_AGG(CASE WHEN Type = 1 THEN Number END, ' & ') Cell,
STRING_AGG(CASE WHEN Type = 2 THEN Number END, ' & ') Home,
STRING_AGG(CASE WHEN Type = 3 THEN Number END, ' & ') Work
From table

MS SQL Combining 5 columns to 3 columns

I am trying to figure out how to combine 5 columns to 3 columns and avoiding duplicities at the same time.
I have been thinking about it for a few days and I can't figure out any solution so far, so I have decided to ask for help here.
Basically right now we use 5 columns in our database let's say A,B,C,D,E and somebody from our company has decided that we will be moving this information to new 3 columns let's call them NEW_1,NEW_2,NEW_3, because there are no cases when we would have more than 3 values per row in the DB.
I need to somehow extract those 5 columns and get them to just 3 columns without repeating them.
So far I was thinking about and trying using CASE, but I can't figure it out how to stop it from showing the same value in all 3 NEW columns. I was thinking about assigning some variables to determine which columns to skip in select CASE, but I have found out that I can't do it like that.
If someone could at least direct me to the right way I would really appreciate it.
SELECT CASE
WHEN A is not null THEN A
WHEN B is not null THEN B
WHEN C is not null THEN C
WHEN D is not null THEN D
WHEN E is not null THEN E
ELSE NULL
END as NEW_1,
CASE
WHEN B is not null THEN B
WHEN C is not null THEN C
WHEN D is not null THEN D
WHEN E is not null THEN E
ELSE NULL
END as NEW_2,
CASE
WHEN C is not null THEN C
WHEN D is not null THEN D
WHEN E is not null THEN E
ELSE NULL
END as NEW_3
Here is a option where we unpivot the data and then apply a conditional aggregation within a CROSS APPLY
Example
Declare #YourTable Table ([A] varchar(50),[B] varchar(50),[C] varchar(50),[D] varchar(50),[E] varchar(50))
Insert Into #YourTable Values
(1,2,3,NULL,NULL)
,(NULL,4,NULL,5,NULL)
,(NULL,null,6,7,8)
,(9,NULL,NULL,NULL,NULL)
Select A.*
,B.*
From #YourTable A
Cross Apply (
Select Val1 = max(case when ColNr=1 then Value end)
,Val2 = max(case when ColNr=2 then Value end)
,Val3 = max(case when ColNr=3 then Value end)
From (
Select ColNr = row_number() over (order by Seq)
,B1.*
From (values (1,A)
,(2,B)
,(3,C)
,(4,D)
,(5,E)
) B1(Seq,Value)
Where Value is not null
) B2
) B
Returns
Just for Fun, here is an XML version
Select A.*
,Val1 = XMLData.value('/x[1]','varchar(max)')
,Val2 = XMLData.value('/x[2]','varchar(max)')
,Val3 = XMLData.value('/x[3]','varchar(max)')
From #YourTable A
Cross Apply ( values ( convert(xml,
concat('<x>'+A+'</x>'
,'<x>'+B+'</x>'
,'<x>'+C+'</x>'
,'<x>'+D+'</x>'
,'<x>'+E+'</x>'
) ) ) ) B(XMLData)
I like John's answer and probably better than mine, but here's a slightly different version if the columns are fixed to a specific number.
Build a delimited string of the column values, then use xml to extract the 1st, 2nd, 3rd values.
Declare #YourTable Table ([A] varchar(50),[B] varchar(50),[C] varchar(50),[D] varchar(50),[E] varchar(50));
Insert Into #YourTable Values
(1,2,3,NULL,NULL),(NULL,4,NULL,5,NULL),(NULL,null,6,7,8),(9,NULL,NULL,NULL,NULL);
WITH CTE AS (
SELECT CASE WHEN a IS NULL THEN '' ELSE a + '~' END +
CASE WHEN b IS NULL THEN '' ELSE b + '~' END +
CASE WHEN c IS NULL THEN '' ELSE c + '~' END +
CASE WHEN d IS NULL THEN '' ELSE d + '~' END +
CASE WHEN e IS NULL THEN '' ELSE e + '~' END AS Combined
FROM #YourTable
)
SELECT
ISNULL(CAST(N'<x>' + REPLACE(Combined, '~', N'</x><x>') + N'</x>' AS XML).value('/x[1]', 'nvarchar(max)'), '') [new_1],
ISNULL(CAST(N'<x>' + REPLACE(Combined, '~', N'</x><x>') + N'</x>' AS XML).value('/x[2]', 'nvarchar(max)'), '') [new_2],
ISNULL(CAST(N'<x>' + REPLACE(Combined, '~', N'</x><x>') + N'</x>' AS XML).value('/x[3]', 'nvarchar(max)'), '') [new_3]
FROM CTE;

How to efficiently concatenate fields that may be null?

I have a front-end field in which the user should see the values of several fields, concatenated with commas. Which is easy enough if the fields are always populated, but that is not the case. In order to avoid extra commas and spaces I came up with:
concat(
[field_one],
case when [field_one] is not null and [field_two] is not null then ', ' end,
[field_two],
case when ([field_two] is not null or [field_one] is not null) and [field_three] is not null then ', ' end,
[field_three]
) as [list_field]
Which works well enough for three fields. But the specs have changed and more fields will be added. The case statements will quickly get out of hand since they're referencing all previous fields. Is there an efficient way to do something like this?
Here is one method:
select stuff( coalesce(', ' + field_one, '') +
coalesce(', ' + field_two, '') +
coalesce(', ' + field_three, ''), 1, 2, '')
The three expressions add a ', ' before each non-null field. The stuff() removes the first one.
The NullIf() is to trap empty/non-null values. Optional if you only have nulls and values.
Example
Declare #YourTable table (field_one varchar(50),field_two varchar(50),field_three varchar(50))
Insert Into #YourTable values
('a','b','c')
,('a',null,'c')
,('a',null,null)
,('a','b',null)
,(null,'b',null)
Select *
,list_field = stuff( concat(
', '+nullif([field_one],'')
,', '+nullif([field_two],'')
,', '+nullif([field_three],'')
)
,1,2,'')
From #YourTable
Returns
field_one field_two field_three list_field
a b c a, b, c
a NULL c a, c
a NULL NULL a
a b NULL a, b
NULL b NULL b
You can actually take advantage of the fact that NULL + anything = NULL and the CONCAT function's NULL handling ability. It makes for a cleaner syntax without all of the COALESCE / ISNULL gunk...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
Col_1 VARCHAR(20) NULL,
Col_2 VARCHAR(20) NULL,
Col_3 VARCHAR(20) NULL
);
INSERT #TestData (Col_1, Col_2, Col_3) VALUES
('Bob', 'A.', 'Jones'),
('123 Some St.', NULL, 'Jacksonville'),
(NULL, 'R.', 'Smith'),
('Roy', 'Finch', NULL),
(NULL, NULL, 'Prince'),
(NULL, NULL, NULL),
('Arnold', NULL, NULL);
SELECT
ConcatString = CONCAT(td.Col_1 + ' ', td.Col_2 + ' ', td.Col_3)
FROM
#TestData td;
Output...
ConcatString
--------------------------------------------------------------
Bob A. Jones
123 Some St. Jacksonville
R. Smith
Roy Finch
Prince
Arnold
I have not tested it, but I believe that this will work on any ANSI compliant database. This probably presumes that the fields are CHAR type or that you will convert them with something like CONVERT() in SQL Server or TO_CHAR() in Oracle.
SELECT
CONCAT(
COALESCE(field_one, '')
,',',COALESCE(field_two, '')
,',',COALESCE(field_three, '')
)
FROM ...
Here is a question about STUFF(). Oracle equivalent to SQL Server STUFF function?

How to split a single column values to multiple column values?

I have a problem splitting single column values to multiple column values.
For Example:
Name
------------
abcd efgh
ijk lmn opq
asd j. asdjja
asb (asdfas) asd
asd
and I need the output something like this:
first_name last_name
----------------------------------
abcd efgh
ijk opq
asd asdjja
asb asd
asd null
The middle name can be omitted (no need for a middle name) The columns are already created and need to insert the data from that single Name column.
Your approach won't deal with lot of names correctly but...
SELECT CASE
WHEN name LIKE '% %' THEN LEFT(name, Charindex(' ', name) - 1)
ELSE name
END,
CASE
WHEN name LIKE '% %' THEN RIGHT(name, Charindex(' ', Reverse(name)) - 1)
END
FROM YourTable
An alternative to Martin's
select LEFT(name, CHARINDEX(' ', name + ' ') -1),
STUFF(name, 1, Len(Name) +1- CHARINDEX(' ',Reverse(name)), '')
from somenames
Sample table
create table somenames (Name varchar(100))
insert somenames select 'abcd efgh'
insert somenames select 'ijk lmn opq'
insert somenames select 'asd j. asdjja'
insert somenames select 'asb (asdfas) asd'
insert somenames select 'asd'
insert somenames select ''
insert somenames select null
;WITH Split_Names (Name, xmlname)
AS
(
SELECT
Name,
CONVERT(XML,'<Names><name>'
+ REPLACE(Name,' ', '</name><name>') + '</name></Names>') AS xmlname
FROM somenames
)
SELECT
xmlname.value('/Names[1]/name[1]','varchar(100)') AS first_name,
xmlname.value('/Names[1]/name[2]','varchar(100)') AS last_name
FROM Split_Names
and also check the link below for reference
http://jahaines.blogspot.in/2009/06/converting-delimited-string-of-values.html
What you need is a split user-defined function. With that, the solution looks like
With SplitValues As
(
Select T.Name, Z.Position, Z.Value
, Row_Number() Over ( Partition By T.Name Order By Z.Position ) As Num
From Table As T
Cross Apply dbo.udf_Split( T.Name, ' ' ) As Z
)
Select Name
, FirstName.Value
, Case When ThirdName Is Null Then SecondName Else ThirdName End As LastName
From SplitValues As FirstName
Left Join SplitValues As SecondName
On S2.Name = S1.Name
And S2.Num = 2
Left Join SplitValues As ThirdName
On S2.Name = S1.Name
And S2.Num = 3
Where FirstName.Num = 1
Here's a sample split function:
Create Function [dbo].[udf_Split]
(
#DelimitedList nvarchar(max)
, #Delimiter nvarchar(2) = ','
)
RETURNS TABLE
AS
RETURN
(
With CorrectedList As
(
Select Case When Left(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
+ #DelimitedList
+ Case When Right(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
As List
, Len(#Delimiter) As DelimiterLen
)
, Numbers As
(
Select TOP( Coalesce(DataLength(#DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
From sys.columns As c1
Cross Join sys.columns As c2
)
Select CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
, Substring (
CL.List
, CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen
, CharIndex(#Delimiter, CL.list, N.Value + 1)
- ( CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen )
) As Value
From CorrectedList As CL
Cross Join Numbers As N
Where N.Value <= DataLength(CL.List) / 2
And Substring(CL.List, N.Value, CL.DelimiterLen) = #Delimiter
)
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(rent, ' ', 1), ' ', -1) AS currency,
SUBSTRING_INDEX(SUBSTRING_INDEX(rent, ' ', 3), ' ', -1) AS rent
FROM tolets
I used it recently:
select
substring(name,1,charindex(' ',name)-1) as Col1,
substring(name,charindex(' ',name)+1,len(name)) as Col2
from TableName
Here is how I did this on a SQLite database:
SELECT SUBSTR(name, 1,INSTR(name, " ")-1) as Firstname,
SUBSTR(name, INSTR(name," ")+1, LENGTH(name)) as Lastname
FROM YourTable;
Hope it helps.

Coalesce and Pivot in TSQL

I am having trouble figuring out how to coalesce or pivot on a SQL recordset that looks like this:
ID VALUE GROUP
3 John 18
4 Smith 18
5 Microsoft 18
3 Randy 21
4 Davis 21
5 IBM 21
etc
and I want formatted like this
NEWVALUE GROUP
Smith, John (Microsft) 18
Davis, Randy (IBM) 21
thanks for any suggestions and help!
This is what i done, i hope it fits for you
DECLARE #t table (id int, value VARCHAR(20), grupo int)
INSERT #T VALUES (3, 'John', 18)
INSERT #T VALUES (4, 'Smith', 18)
INSERT #T VALUES (5, 'Microsoft', 18)
INSERT #T VALUES (3, 'Randy', 21)
INSERT #T VALUES (4, 'Davis', 21)
INSERT #T VALUES (5, 'IBM', 21)
SELECT grupo, (SELECT value FROM #t t2 WHERE t2.grupo = t.grupo AND id = 4) + ', ' +
(SELECT value FROM #t t2 WHERE t2.grupo = t.grupo AND id = 3) + ' (' +
(SELECT value FROM #t t2 WHERE t2.grupo = t.grupo AND id = 5) + ')'
FROM #t t
GROUP BY grupo
SELECT LEFT(gvalue, LEN(gvalue) - 1) AS newvalue, _group
FROM (
SELECT DISTINCT _group
FROM mytable
) qo
CROSS APPLY
(
SELECT value + ', '
FROM mytable qi
WHERE qi._group = qo._group
FOR XML PATH ('')
) gr(qvalue)
If you always have a set of three hardcoded ID's for each _group, you can just use:
SELECT m3._group, m3.value + ', ' + m4.value + '(' + m5.value + ')' AS newvalue
FROM mytable m3
LEFT JOIN
mytable m4
ON m4._group = m3.group
LEFT JOIN
mytable m5
ON m5._group = m3.group
WHERE m3.id = 3
AND m4.id = 4
AND m5.id = 5
What you need is not pivoted query but a simple select with group by and an aggregate string concatenation function. But i don't remember the exact function in tsql.
Update: there is no aggregate concatenation function in tsql but since sql2005 you can write your own extension to implement such function. There is plenty of examples on google search for: tsql 2005 concatenation aggregate example.
This is a little hokey, but I think it should work reasonably well for a small data set. If you've got a lot of data you need to create a cursor and a loop.
select max(case when ID = 4 then VALUE else null end) + ', ' +
max(case when ID = 4 then VALUE else null end) + '( ' +
max(case when ID = 5 then VALUE else null end) + ') as NEWVALUE,
[GROUP]
group by [GROUP]