Concat columns in different rows with same ID SQL Server 2005 - sql

I am looking to concat a column in each row that that holds text input....
I am using SQL Server 2005
The rows look like this
Number Date Update Time description
------ ----- ----------- -------------
0123 01/01/2015 01/07/2015 Hello, I want to
0123 01/01/2015 01/01/2015 Concat these columns
Hopefully this is easy and I am just being a simpleton

Because you are dealing free form text, I think it is better to explicitly convert the XML back to a character data type:
SELECT t.Number,
STUFF((SELECT ' ' + cast(t2.description AS nvarchar(max) )
FROM <tablen> t2
WHERE t2.Number = t.Number
FOR XML PATH(''), TYPE
).VALUE('.', 'nvarchar(max)'
), 1, 1, '' ) AS Description
FROM <table> t
GROUP BY t.Number;
This prevents problems with characters such as &, <, and >.

You could use this approach:
SELECT A.Number, MAX(A.[Date]) AS [Date], MAX(A.[Update Time]) AS [Update Time]
, STUFF((SELECT ' ' + B.description AS [text()]
FROM table1 B
WHERE A.Number = B.Number
FOR XML PATH('')), 1, 1, '' ) AS Description
FROM table1 A
GROUP BY A.Number

Related

Stuff with group by on DATENAME function

Situation:
Let there be a table ALPHA which contains a column ALPHA.ID_BETA (Foreign Key on Table BETA) and a column ALPHA.CREATIONDATE (DATETIME NOT NULL).
Now assume the following records in Table ALPHA:
ID
CREATIONDATE (YYYY-MM-DD)
ID_BETA
1
2022-05-26 00:00:00.000
1
2
2022-02-02 00:00:00.000
1
3
2022-01-28 00:00:00.000
1
4
2022-01-02 00:00:00.000
1
Now imagine Table BETA to look like this (i left out other columns for simplicity:
ID
1
Desired Output:
Is a value that concatenates all values (Format: DATENAME + YYYY) of CREATIONDATE for a single ID_BETA Ordered by date ascending. In this example, the output should be January 2022, February 2022, May 2022 (obviously depending on Language settings)
What I have tried:
SELECT STUFF(
(SELECT ', '
+ DATENAME(MONTH,(ALPHA.CREATIONDATE)) + DATENAME(YEAR, ALPHA.CREATIONDATE)
FROM ALPHA
WHERE ALPHA.ID_BETA = 1
GROUP BY ALPHA.CREATIONDATE
ORDER BY ALPHA.CREATIONDATE ASC
FOR XML PATH('')),1, 1, '')
This however will not give me distinct values. Trying out the obvious DISTINCT statement gives me the following error:
Server: Msg 145, Level 15, State 1, Line 1 ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
Note that I cannot solve this problem with the "new" STRING_AGG function since it's only supported from SQL-Server2017 upwards.
You need to group and sort by EOMONTH(CREATIONDATE) in order to group by a single date per month, rather than grouping just by CREATIONDATE.
Note also that you need .value to unescape the XML, and the third parameter of STUFF should be the same as the length of the separator
SELECT STUFF(
(SELECT
', ' + DATENAME(MONTH, EOMONTH(a.CREATIONDATE)) + DATENAME(YEAR, EOMONTH(a.CREATIONDATE))
FROM ALPHA a
WHERE a.ID_BETA = 1
GROUP BY
EOMONTH(a.CREATIONDATE)
ORDER BY
EOMONTH(a.CREATIONDATE)
FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(', '), '')
If you want to do this per row of BETA you can use CROSS APPLY or a subquery:
SELECT STUFF(
(SELECT
', ' + DATENAME(MONTH, EOMONTH(a.CREATIONDATE)) + DATENAME(YEAR, EOMONTH(a.CREATIONDATE))
FROM ALPHA a
WHERE a.ID_BETA = b.ID
GROUP BY
EOMONTH(a.CREATIONDATE)
ORDER BY
EOMONTH(a.CREATIONDATE)
FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(', '), '')
FROM BETA b;
As an error mesage says, order by exactly the expression in the select clause
SELECT STUFF(
(SELECT distinct ', '
+ DATENAME(MONTH,(ALPHA.CREATIONDATE)) + DATENAME(YEAR, ALPHA.CREATIONDATE)
FROM ALPHA
WHERE ALPHA.ID_BETA = 1
GROUP BY ALPHA.CREATIONDATE
ORDER BY ', '
+ DATENAME(MONTH,(ALPHA.CREATIONDATE)) + DATENAME(YEAR, ALPHA.CREATIONDATE) ASC
FOR XML PATH('')),1, 1, '')

Combining specific sql query results into one string

I have the following query;
SELECT custom.name, instance_id
FROM table1 tb
WHERE tb.instance_id = 1111 OR tb.instance_id = 2222
This returns the following results;
test, 1111
test1, 1111
test3, 1111
tabletest, 2222
tabletest1, 2222
tabletest2, 2222
I would like the ability to match the instances_id, and combine the matching rows into a single string.
i.e.
test;test1;test3
tabletest;tabletest1;tabletest2
I can get a single string but at the moment this grabs all the results and puts it into a single string.
STUFF((
SELECT custom.name + ';'
FROM table1 tb
WHERE tb.instance_id = 1111 OR tb.instance_id = 222
FOR XML PATH(' '), TYPE.value('.', 'NVARCHAR(MAX)'), 1, 0, ' ')
this results in
test;test1;test3;tabletest;tabletest1;tabletest2
Unfortunately I cannot upgrade past sql server version 15 which perhaps limits me.
You need a correlation clause in the subquery. I would suggest:
SELECT v.instance_id,
STUFF((SELECT ';' + tb.name
FROM table1 tb
WHERE tb.instance_id = v.instance_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'
), 1, 1, ' '
)
FROM (VALUES (1111), (2222)) v(instance_id);
Here is a db<>fiddle.
Data
drop table if exists dbo.tTable;
go
create table dbo.tTable(
[name] varchar(100) not null,
instance_id int not null);
insert dbo.tTable values
('test',1111),
('test1',1111),
('test3',1111),
('test',2222),
('test1',2222),
('test2',2222);
Query
select instance_id,
stuff((select ';' + cast([name] as varchar(100))
from tTable c2
where t.instance_id = c2.instance_id
order by [name] FOR XML PATH('')), 1, 1, '') [value1]
from tTable t
group by instance_id;
Output
instance_id value1
1111 test;test1;test3
2222 test;test1;test2

SQL how to put values on one line

It is necessary that in the second column in a single line should be all related accounts.
This shows an error
Conversion failed when converting the varchar value ',' to data type int.
SELECT [UserID],
STUFF((SELECT ', ' + UserID
FROM #RelatedIDs
WHERE (UserID = t.UserID)
FOR XML PATH('')) ,1,1,'') AS RelIDs
FROM #RelatedIDs t
GROUP BY UserID
You could cast the integer value to a varchar:
SELECT [UserID],
STUFF((SELECT ',' + CAST(UserID as VARCHAR(100))
FROM #RelatedIDs
WHERE (UserID = t.UserID)
FOR XML PATH('')) ,1,1,'') AS RelIDs
FROM #RelatedIDs t
GROUP BY UserID
If you are running a recent version of SQL Server (2017 or higher), you can get the same result in a much less obsfucated manner with string_agg():
SELECT t.UserID, STRING_AGG(r.UserID, ',') RelIDs
FROM #RelatedIDs t
INNER JOIN #RelatedIDs r on r.UserID = t.UserID
GROUP BY t.UserID
With the query put this way, it is plain to see that it makes little sense. The self-join operates on the same column as the one that defines the group, so this will just generate a list of identical UserIDs in column RelIDs (one per occurence of the given UserID in the original query).
Use CONCAT() instead of +:
SELECT [UserID],
STUFF((SELECT CONCAT(', ', UserID)
FROM #RelatedIDs ri
WHERE ri.UserID = t.UserID
FOR XML PATH('')
), 1, 2, '') AS RelIDs
FROM #RelatedIDs t
GROUP BY UserID;
Notice that I also changed the stuff arguments from 1, 1 to 1, 2. That is because you have a space after the comma.
Your correlation clause also suggests that the results will not be very interesting, when you get this to work.

SQL Server : show campaigns that a phone number appears in

I'm trying to get a report done within SQL Server that shows each sales campaign that a phone number appears in.
The desired result:
Phonenumber | Area Code | Campaign 1 | Campaign 2 (if applicable) etc...
I have the following code:
with cids as
(
select distinct
a.outbound_cid as [CID],
a.areacode as [AreaCode],
a.campaign_id as [Campaign]
from
vicislave...vicidial_campaign_cid_areacodes a
join
LDS_SALES_CAMPAIGNS b on a.campaign_id = b.campaign_id
)
select *
from cids
order by cid
Which returns this result (data example):
In this example, I would get
2012444340 201 ZEPTR ZEACC ZBEASTC ZEPRR InBnd2 ZEPSC ZEJCC ZEJSC ZEPCC ZEASC
I've not worked with cross-tabbing before, but it appears to be something that may work, but I have not been able to make it work like I can. Obviously, I can do the MIN and MAX of each of these, but I don't know of a way to get the data into the one row, even using things like Excel, without manually doing it, which with 1110 results with these, I don't really have time to do it.
Not to ape the help that I got from below, here is the exact code that worked:
select distinct
a.outbound_cid as [CID],
a.areacode as [AreaCode],
a.campaign_id as [Campaign]
into
#CIDs
from
vicislave...vicidial_campaign_cid_areacodes a
join
LDS_SALES_CAMPAIGNS b on a.campaign_id = b.campaign_id
select distinct
CID,
areacode,
Campaign = stuff((select ', ' + c2.campaign
from #CIDs c2
where c2.CID = c.CID
for xml path(''), type).value('.', 'nvarchar(MAX)'), 1, 1, '')
from
#cids c
drop table #CIDs
If you use SQL server, you can use STUFF function. You can follow my sample. Hope to help, my friend!
Create table Test(CID nvarchar(10)
, AreaCode nvarchar(10)
, Campaign nvarchar(10))
Insert into Test(CID, AreaCode, Campaign)
values('2012', '201', 'ABC')
Insert into Test(CID, AreaCode, Campaign)
values('2012', '201', 'XYZ')
Insert into Test(CID, AreaCode, Campaign)
values('2014', '201', 'aaa')
Insert into Test(CID, AreaCode, Campaign)
values('2014', '201', 'bbb')
-----------
SELECT distinct CID
, Campaign = STUFF((
SELECT ',' + t2.Campaign
FROM Test t2
WHERE t.CID = t2.CID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM Test t
ORDER BY t.CID
To obtain a single record from any table "TABLE" with a field "field" you have to do
SELECT ';'+rtrim(field)
FROM TABLE FOR XML PATH('')
Tha will return a single record with all the fields concatenated with ";"
in your case you should do :
select ';'+campaign from cids FOR XML PATH('')
order by cid
of course you can even group by CID Column if you need...
SELECT C.CID, (
select ';'+campaign from cids
where cids.CID=C.CID
FOR XML PATH(''))
from CIDS C
group by CID
that would do the trick

SQL - Combine Multiple Columns with Multiple Rows into one row

What I'm trying to do:
I have records in a SQL table where there are 5 columns and thousands of rows.
The rows share duplicate data (i.e. account number) but what makes each unique is that data in one of the columns is different.
As an example:
col1|col2|col3|col4|col5
------------------------
123|abc|456|def|789
123|abc|456|def|date
But the columns can have different values, not necessarily always in column 5.
Here's what I started with:
SELECT TOP (15) stuff((
SELECT ', ' + te.[accountid]
,te.[char1]
,te.[date]
,te.[date2]
,te.[char2]
FROM D AS te
INNER JOIN D AS tue ON tue.[accountid] = te.[accountid]
WHERE tue.[accountid] = ue.[accountid]
FOR XML path('')
,type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
FROM D AS ue
GROUP BY ue.[accountid]
But I get a monster long string that includes the duplicate rows in one column. I'm not sure what else to try so any insight would be appreciated.
If I had to guess, you have an unnecessary self join in the subquery:
SELECT TOP (15) stuff((
SELECT ', ' + te.[accountid], te.[char1], te.[date], te.[date2], te.[char2]
FROM D te
WHERE te.[accountid] = ue.[accountid]
FOR XML path(''), type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
FROM D ue
GROUP BY ue.[accountid];
You might also want SELECT DISTINCT in the subquery.
Use UNION to get rid of all the duplicate values and use your FOR XML PATH on the output to append it to a single string:
SELECT TOP (15) stuff((
SELECT ', ' + CAST(te.[accountid] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[char1] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[date] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[date2] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[char2] AS varchar(255)) FROM D
FOR XML path('')
,type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
Untested, treat as pseudo-code to give the general idea.