Combining specific sql query results into one string - sql

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

Related

Concat columns in different rows with same ID SQL Server 2005

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

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.

TSQL Select query that generates output similar to the ms access multiple value fields

I have tables in SQL Server 2008 such as:
TopicTable
TopicID: nvarchar (Primary Key)
ProgID: nvarchar
topic1: bit
topic2: bit
topic3: bit
topic4: bit
The topic table looks something like the following:
TopicID ProgID topic1 topic2 topic3 topic4
topic001 prog001 1 1 0 0
topic002 prog002 1 0 1 1
topic003 prog003 1 0 0 0
topic004 prog004 1 1 1 1
Program table:
ProgID: nvarchar (Primary Key)
ProgramName: nvarchar
The Program table looks like this:
ProgID ProgramName
prog001 programA
prog002 programB
prog003 programC
prog004 programD
I want to create a view to get the output like:
ProgID ProgramName Topic
prog001 programA topic1,topic2
prog002 programB topic1,topic3,topic4
prog003 programB topic1
prog004 programD topic1,topic2,topic3,topic4
Please can someone help me how to get this.
Thank You.
It would look like this:
;WITH cteTopics AS (
SELECT T.ProgID
,STUFF((
SELECT T1.TopicID + ','
FROM TopicTable T1
WHERE T1.ProgID = T.ProgID
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Topics]
FROM TopicTable T
GROUP BY T.ProgID)
SELECT P.ProgID, P.ProgramName, T.Topics
FROM Program P
LEFT JOIN cteTopics T ON T.ProgID = P.ProgID
http://sqlfiddle.com/#!3/b9e4a/4
You will have some extra commas here but you can tweak the code a little bit more to eliminate the extra commas . this is what I have got for you so far
CREATE Table Topic (Topic NVARCHAR(20), Programe NVARCHAR(20), Topic1 bit, Topic2 bit,Topic3 bit,Topic4 bit)
GO
INSERT INTO Topic
VALUES
('topic001','prog001',1,1,0,0),
('topic002','prog002',1,0,1,1),
('topic003','prog003',1,0,0,0),
('topic004','prog004',1,1,1,1)
GO
CREATE TABLE Programe (P_ID NVARCHAR(20) , Name NVARCHAR(20))
GO
INSERT INTO Programe VALUES
('prog001','programA'),
('prog002','programB'),
('prog003','programC'),
('prog004','programD')
GO
View Definition
CREATE VIEW vw_ViewName
AS
SELECT P_ID, Name, ISNULL(STUFF(L1.Topic1L, 1, 1 , '') + ', ', '') + ISNULL(STUFF(L2.Topic2L, 1, 1, '') + ', ', '')
+ ISNULL( STUFF(L3.Topic3L, 1, 1, '')+ ', ', '') + ISNULL(STUFF(L4.Topic4L, 1, 1, '')+ ', ', '') AS Topics
FROM Programe P CROSS APPLY (
SELECT ' ' + CASE WHEN Topic1 = 1 THEN 'Topic1' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L1(Topic1L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic2 = 1 THEN 'Topic2' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L2(Topic2L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic3 = 1 THEN 'Topic3' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L3(Topic3L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic4= 1 THEN 'Topic4' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L4(Topic4L)
RESULT SET
P_ID Name Topics
prog001 programA Topic1, Topic2,
prog002 programB Topic1, Topic3, Topic4,
prog003 programC Topic1,
prog004 programD Topic1, Topic2, Topic3, Topic4,

SQL, questions about join

I have two tables in sql 2012: name and prod with structure:
name: id int increment, name1 nvarchar(50)
prod: id int increment, products nvarchar(50), id_name int
Values for table are:
name table:
Id name1
1 pop
2 andi
prod table:
Id products id_name
1 coke 1
2 pizza 1
3 orange 2
I have done this query:
select name.name1, prod.product, prod.id_name
from name
join prod on name.id=prod.id_name
How can I obtain this result:
pop ->coke, pizza
andi->orange
unfortunately, there's no easy way to do it in SQL Server. Known solutions are:
xml trick (see below);
using variable to accumulate data (don't work for multiple group rows, only with cursor);
custom CLR aggregate;
here's xml:
select
n.name1,
stuff(
(
select ', ' + p.product
from prod as p
where p.id_name = n.id
for xml path(''), type).value('.', 'nvarchar(max)')
, 1, 2, '') as products
from name as n
sql fiddle demo
here's variable:
declare #product nvarchar(max), #id int
select #id = 1
select #product = isnull(#product + ', ', '') + product
from prod
where id_name = #id
select name1, #product as products
from name
where id = #id
sql fiddle demo
try this:
SELECT
G.id,
G.name1,
stuff(
(select cast(',' as varchar(10)) + U.product
from prod U
WHERE U.id_name = G.id
order by U.product
for xml path('')
), 1, 1, '') AS prod
FROM name G
ORDER BY G.name1 ASC
sqlfiddle
select
n.nameid [id],
n.name [name],
count(*)[count],
stuff(
(
select ', ' + p.prod
from prodtbl as p
where p.nameid = n.nameid
for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '') as products
from nametbl n, prodtbl p
where p.nameid = n.nameid
group by n.nameid, n.name
order by [id];

Flatten SQL Server Table to a string

I have a table like:
ID | Value
----------------
1 | One
2 | Two
3 | Three
What I need to do is create a single string from these values, in the format:
'1: One, 2: Two, 3: Three'
I know how to do this using cursors, but it will be used as a column in a view, so it's not really a performant option.
Any pointers?
WITH T(ID,Value) AS
(
SELECT 1, 'One' UNION ALL
SELECT 2, 'Two' UNION ALL
SELECT 3, 'Three'
)
SELECT STUFF(
(SELECT ', ' + CAST(ID as varchar(11)) + ': ' + Value
FROM T
FOR XML PATH (''))
, 1, 2, '')
Have a look at something like
DECLARE #Table TABLE(
ID INT,
Value VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'One'
INSERT INTO #Table SELECT 2,'Two'
INSERT INTO #Table SELECT 3,'Three'
SELECT STUFF(
(
SELECT ', ' + CAST(ID AS VARCHAR(MAX)) + ': ' + Value
FROM #Table
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
)
SELECT STUFF((
SELECT ' ' + CAST(ID AS VARCHAR(2)) + ': '+ Value
FROM dbo.Table
FOR XML PATH('')
), 1, 1, ''
) As concatenated_string
DECLARE #ans VARCHAR(max)
SET #ans=''
SELECT #ans = #ans + str(id)+':'+value FROM table
SELECT #ans
Change the max to 8000 if your version of SQL doesn't support it
I would simply not do this in the database if at all possible. It's not designed for formatting data in a certain way; let the calling application handle that.
In C# (assuming data is an instance of SqlDataReader):
var l = new List<string>();
while (reader.Read())
l.Add(string.Format("{0}: {1}", reader[0], reader[1]));
var s = string.Join(", ", l.ToArray());