SQL FIDDLE DEMO HERE
I have this table structure for Workers table:
CREATE TABLE Workers
(
[Name] varchar(250),
[IdWorker] varchar(250),
[work] varchar(250)
);
INSERT INTO Workers ([Name], [IdWorker], [work])
values
('Sam', '001', 'Director'),
('Julianne', '002', 'Recepcionist'),
('Jose', '003', 'Recepcionist');
What I want is to get for each job the name of workers separate by commas, like this:
Director Recepcionist
------- ------------
Sam Julianne, Jose
I tried to used this query:
DECLARE #rec VARCHAR(MAX)
SELECT #rec = COALESCE(#rec + ', ', '') + Name from
Workers where job = 'Recepcionist' SELECT #dir AS Recepcionist
And I got this result:
Recepcionist
------------
Julianne, Jose
This works only for one job, but I need to add more, so I tried then to use this query:
SELECT [Director] , [Recepcionist]
FROM
(SELECT [job], [Name],RANK() OVER (PARTITION BY [job] ORDER BY [job],[Name]) as rnk
FROM Workers ) p
PIVOT(
Min([Name])
FOR [job] IN
( [Director] , [Recepcionist] )
) AS pvt
And I get this result:
Director Recepcionist
-------- ------------
Sam Julianne
Jose
I need to get the results in the same row separate by commas, how can I combine the two querys?
I accept suggestions, thanks.
I am assuming in your example query you meant job to reference the work column. The following query should do the job as per your sql fiddle.
SELECT STUFF(
(
SELECT ', ' + cast([Name] as varchar(max))
FROM Workers
WHERE [work] = 'Recepcionist'
FOR XML PATH('')
), 1, 2, ''
) AS Recepcionist
,STUFF(
(
SELECT ', ' + cast([Name] as varchar(max))
FROM Workers
WHERE [work] = 'Director'
FOR XML PATH('')
), 1, 2, '') AS Director;
the way you would do this using PIVOT would be like this.
SELECT *
FROM (SELECT [work],
STUFF((SELECT ', ' + [Name]
FROM Workers s
WHERE s.WORK = w.WORK
FOR XML PATH('')),
1, 2, '') AS [workers]
FROM Workers w) t
PIVOT (
MAX([workers])
FOR [work] IN ([Director], [Recepcionist])
) p
another alternative to PIVOT is MAX(CASE)
SELECT MAX(CASE WHEN [work] = 'Director' THEN [workers] END) AS [Director],
MAX(CASE WHEN [work] = 'Recepcionist' THEN [workers] END) AS [Recepcionist]
FROM (SELECT [work],
STUFF((SELECT ', ' + [Name]
FROM Workers s
WHERE s.WORK = w.WORK
FOR XML PATH('')),
1, 2, '') AS [workers]
FROM Workers w) t
both of these allow you to separate the data by other fields like Company or Department
you can do it like this
SELECT
t1.job
,STUFF(
(SELECT
', ' + t2.Name
FROM Workers t2
WHERE t1.job =t2.job
ORDER BY t2.Name
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS ChildValues
FROM Workers t1
GROUP BY t1.job
Related
Using SQL-Server 2012
I have the following Table:
Id Description
6192 Salzburg
6193 Salzburg
6194 Salzburg
6196 Innsbruck
6197 Innsbruck
6198 Innsbruck
6199 Innsbruck
6201 Bregenz
6202 Bregenz
6203 Bregenz
I want to Select each Distinct "Description" with all the Id's together in one string:
Description Ids
Salzburg '6192,6193,6194'
Innsbruck '6196,6197,6198'
I saw some similar code on this site [How to concatenate text from multiple rows into a single text string in SQL server?, but I couldn't figure it out yet for my purpose (don't want to use XML Path!). Here is what I have tried so far:
DECLARE #ids AS Nvarchar(MAX)
SELECT #ids = COALESCE(#ids + ',', '') + CAST(t.Id AS nvarchar(5))
FROM (SELECT tmp.Id FROM (SELECT id, [Description] FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1) as tmp
WHERE [Description] = tmp.[Description]) AS t
SELECT #ids
--SELECT DISTINCT [Description], #ids AS IDs FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1 AND Id IN (#ids)
I can't really get my head around it, and would appreciate any help on it.
You can try using STUFF() function
SELECT description, Ids = STUFF(
(SELECT ',' + Id
FROM tblMasterPropValues t1
WHERE t1.description = t2.description
FOR XML PATH (''))
, 1, 1, '') from tblMasterPropValues t2
group by description;
For that FOR XML PATH() is the right clause so, you can do :
SELECT DISTINCT v.description, STUFF(v1.ids, 1, 1, '''') + ''''
FROM tblMasterPropValues v CROSS APPLY
(SELECT ', '+ CAST(v1.Id AS VARCHAR(255))
FROM tblMasterPropValues v1
WHERE v1.description = v.description
FOR XML PATH('')
) v1(ids);
You can also make it by using recursive CTE
DECLARE #tblMasterPropValues TABLE (Id INT, Description VARCHAR(20))
INSERT INTO #tblMasterPropValues VALUES
(6192 , 'Salzburg'),
(6193 , 'Salzburg'),
(6194 , 'Salzburg'),
(6196 , 'Innsbruck'),
(6197 , 'Innsbruck'),
(6198 , 'Innsbruck'),
(6199 , 'Innsbruck'),
(6201 , 'Bregenz'),
(6202 , 'Bregenz'),
(6203 , 'Bregenz')
;WITH Tbl AS
(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY Description ORDER BY Id) AS RN,
COUNT(*) OVER(PARTITION BY Description) AS CNT
FROM #tblMasterPropValues
)
, Rcr AS (
SELECT *, CAST(Id AS varchar(max)) Ids
FROM Tbl WHERE RN = 1
UNION ALL
SELECT T.*, Rcr.Ids + ',' + CAST(T.Id AS VARCHAR(10)) Ids
FROM Rcr
INNER JOIN Tbl T ON T.RN = Rcr.RN + 1 and Rcr.Description = T.Description
)
SELECT RN, Description, Ids FROM Rcr
WHERE RN = CNT
Result:
Description Ids
-------------------- -----------------------
Salzburg 6192,6193,6194
Innsbruck 6196,6197,6198,6199
Bregenz 6201,6202,6203
Try this:
DECLARE #Table TABLE(ID INT, Description VARCHAR(25))
INSERT INTO #Table
VALUES (6192,'Salzburg' )
,(6193,'Salzburg' )
,(6194,'Salzburg' )
,(6196,'Innsbruck')
,(6197,'Innsbruck')
,(6198,'Innsbruck')
,(6199,'Innsbruck')
,(6201,'Bregenz' )
,(6202,'Bregenz' )
,(6203,'Bregenz' )
Query:
SELECT DISTINCT T2.Description,
SUBSTRING(
(
SELECT ','+CAST(T1.ID AS VARCHAR) AS [text()]
FROM #Table T1
WHERE T1.Description = T2.Description
ORDER BY T1.Description
FOR XML PATH ('')
), 2, 1000) [Ids]
FROM #Table T2
Result:
Description Ids
Bregenz 6201,6202,6203
Innsbruck 6196,6197,6198,6199
Salzburg 6192,6193,6194
Code:
ISNULL(LTRIM(STUFF( (SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')), 1, 1, '')),'___________') AS Pipe_Product
How can I do this?
Another approach can be to add a ROW_NUMBER into the sub-query to decide whether a comma or and should be inserted. This should be faster since you don't have separate queries against the same PipelineInformation table both of which are correlated sub-queries.
DECLARE #PL TABLE (Pipe_Product VARCHAR(50), Project_ID INT)
INSERT #PL VALUES ('gas', 1),('oil', 1),('orange juice', 1), ('milk', 2), ('honey', 2)
SELECT
TI.Project_ID,
SUBSTRING((
SELECT
CASE WHEN RowNum = 1 THEN ' and ' ELSE ', ' END + T.Pipe_Product AS [text()]
FROM (
SELECT
Pipe_Product,
Project_ID,
ROW_NUMBER() OVER (ORDER BY Pipe_Product DESC) AS RowNum
FROM #PL
WHERE Project_ID = TI.Project_ID
) T
ORDER BY RowNum DESC
FOR XML PATH('')
), 3, 4000) AS [Pipe_Product]
FROM (SELECT 1 UNION ALL SELECT 2) AS TI (Project_ID)
The sample data above outputs:
Project_ID Pipe_Product
----------- -----------------------------
1 gas, oil and orange juice
2 honey and milk
Try this edited result instead:
reverse(stuff(reverse(ISNULL(LTRIM(STUFF((
SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')
), 1, 1, '')), '___________')), charindex(' ,', reverse(ISNULL(LTRIM(STUFF((
SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')
), 1, 1, '')), '___________'))), 2, ' dna '))
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,
I am writing a query to get the address for PersonID. Following query is working for me but it only returns with two Addresses. I want to handle the 'n' number of address with a single query. Is there any way to do this?
Many thanks
SELECT
PersonID, PersonName
[Address1], [Address2]
FROM
(
SELECT
P.PersonID,
P.PersonName,
(ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID
FROM tblPerson
INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID
) AS AddressTable
PIVOT
(
MAX(AddressID)
FOR RowID IN ([Address1], [Address2])
) AS PivotTable;
Assuming the following tables and sample data:
USE tempdb;
GO
CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255));
INSERT dbo.tblPerson SELECT 1, 'Bob'
UNION ALL SELECT 2, 'Charlie'
UNION ALL SELECT 3, 'Frank'
UNION ALL SELECT 4, 'Amore';
CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255));
INSERT dbo.tblAddress SELECT 1,1,'255 1st Street'
UNION ALL SELECT 2,2,'99 Elm Street'
UNION ALL SELECT 3,2,'67 Poplar Street'
UNION ALL SELECT 4,2,'222 Oak Ave.'
UNION ALL SELECT 5,1,'36 Main Street, Suite 22'
UNION ALL SELECT 6,4,'77 Sicamore Ct.';
The following query gets the results you want, and shows how it handles 0, 1 or n addresses. In this case the highest number is 3 but you can play with more addresses if you like by adjusting the sample data slightly.
DECLARE #col NVARCHAR(MAX) = N'',
#sel NVARCHAR(MAX) = N'',
#from NVARCHAR(MAX) = N'',
#query NVARCHAR(MAX) = N'';
;WITH m(c) AS
(
SELECT TOP 1 c = COUNT(*)
FROM dbo.tblAddress
GROUP BY PersonID
ORDER BY c DESC
)
SELECT #col = #col + ',[Address' + RTRIM(n.n) + ']',
#sel = #sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x'
+ RTRIM(n.n) + '.Address',
#from = #from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x'
+ RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x'
+ RTRIM(n.n) + '.rn = ' + RTRIM(n.n)
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns) AS n WHERE n.n <= m.c;
SET #query = N';WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName' + #col
+ ' FROM
(
SELECT p.PersonID, p.PersonName, ' + STUFF(#sel, 1, 1, '')
+ CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + #from + '
) AS Addresses;';
PRINT #query;
--EXEC sp_executesql #query;
If you print the SQL you will see this result:
;WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM
(
SELECT p.PersonID, p.PersonName,
[Address1] = x1.Address,
[Address2] = x2.Address,
[Address3] = x3.Address
FROM dbo.tblPerson AS p
LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1
LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2
LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3
) AS Addresses;
If you execute it, you will see this:
I know the query to get here is an ugly mess, but your requirement dictates it. It would be easier to return a comma-separated list as I suggested in my comment, or to have the presentation tier deal with the pivoting.
ID Name
1 A
1 B
1 C
2 X
2 Y
3 P
3 Q
3 R
These are the columns in a table. I want to get output like
ID Company
1 A,B,C
2 X, Y
3 P,Q,R
Restriction is that I cannot use WHILE or CURSOR. Please write a query for the same.
This query should do it - uses FOR XML PATH which is new in SQL Server 2005 - hope you are on 2005 or higher, you didn't clearly specify.....
SELECT
ID,
STUFF(CAST((SELECT ','+Name FROM dbo.YourTable t2
WHERE t2.ID = dbo.YourTable.ID
FOR XML PATH(''), TYPE) AS VARCHAR(MAX)), 1, 1, '') AS 'Company'
FROM
dbo.YourTable
GROUP BY
ID
Here's a solution using the CROSS APPLY method:
select id, sub.names
from (
select distinct id from YourTable
) a
cross apply (
select name + ', ' as [text()]
from YourTable b
where b.id = a.id
for xml path('')
) sub(names)
For 2005 version:
CREATE TABLE dbo.TEST([Type] INTEGER, [Name] NVARCHAR(100), [Qty] INTEGER)
GO
INSERT dbo.TEST VALUES(1, N'a', 5)
INSERT dbo.TEST VALUES(1, N'b', 6)
INSERT dbo.TEST VALUES(2, N'c', 44)
INSERT dbo.TEST VALUES(3, N'd', 1)
GO
select [Type],
[Description] = replace((select [Name] + ':' + cast([Qty] as varchar) as 'data()'
from TEST where [Type] = t.[Type] for xml path('')), ' ', ',')
from dbo.TEST t
group by [Type]
go
drop table dbo.TEST
You can group on the ID to get the unique values, then get the comma separated string for each using a for xml query:
select
a.ID,
substring((
select ', ' + Name
from Test1
where Test1.ID = a.ID
for xml path('')
), 3, 1000) as Company
from
TheTable a
group by
a.ID