SQL - Multiple records in one row - sql

I've trying to create a script that allows me to display multiples records in a one-row, group by a specific column. Below is the code that I worked on. I've done it in Power BI but now I need it on SQL Someone could help me how can I fix this, I appreciate:
MY CODE:
B.WorkOrderCode,
STUFF((SELECT '; ' + A.UserName
FROM [PanatrackerGP].[dbo].[User] AS A
WHERE A.ProfileOid = B.ProfileOid
FOR XML PATH('')), 1, 1, '') [USERS]
FROM [PanatrackerGP].[dbo].[TrxIssueInventory] AS B
WHERE B.WorkOrderCode = 'S12119'
GROUP BY B.ProfileOid, B.WorkOrderCode
ORDER BY 1
------------------------------ OUTPUT ----------------------------------------
WorkOrderCode | USERS
S12119 | GM; FM; FO; GR; RG; TI
S12119 | NC; BS; DNA; CS; JMAGGI; mj; fa; LR; lgm; MS; JPU
-----------------------------------------------------------------------
Only these users should be shown
------------------------------TrxIssueInventory[TABLE]-----------------
WorkOrderCode | CreateUserName
S12119 | FO
S12119 | lgm
-----------------------------------------------------------------------
-----------------------------GOAL OUTPUT---------------------------------
WorkOrderCode | CreateUserName
S12119 | FO ; lgm
-----------------------------------------------------------------------
Thank You

You have to do an additional join within your correlated subquery:
SELECT b.WorkOrderCode,
CreateUserName = STUFF((SELECT CONCAT(';', u.UserName)
FROM [dbo].[User] AS u
INNER JOIN [dbo].[TrxIssueInventory] AS i
ON i.ProfileOid = u.ProfileOid
WHERE i.WorkOrderCode = b.WorkOrderCode
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(1000)'), 1, 1, '')
FROM [dbo].[TrxIssueInventory] AS b
GROUP BY b.WorkOrderCode;
I've also amended your concatenation method slightly to use FOR XML PATH(), TYPE rather than just for XML path as this properly handles special XML Characters. If you had a username that was LGM > this would end up as LGM >, if you don't use TYPE and '.value`.
WORKING DEMO
IF OBJECT_ID(N'tempdb..#TrxIssueInventory', 'U') IS NOT NULL
DROP TABLE #TrxIssueInventory;
IF OBJECT_ID(N'tempdb..#User', 'U') IS NOT NULL
DROP TABLE #User;
CREATE TABLE #TrxIssueInventory (WorkOrderCode INT, ProfileOid INT);
INSERT #TrxIssueInventory VALUES (12119, 1), (12119, 2);
CREATE TABLE #User (ProfileOid INT, UserName VARCHAR(10));
INSERT #User VALUES (1, 'FO'), (2, 'LGM >');
SELECT b.WorkOrderCode,
CreateUserName = STUFF((SELECT CONCAT(';', u.UserName)
FROM #User AS u
INNER JOIN #TrxIssueInventory AS i
ON i.ProfileOid = u.ProfileOid
WHERE i.WorkOrderCode = b.WorkOrderCode
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(1000)'), 1, 1, '')
FROM #TrxIssueInventory AS B
GROUP BY b.WorkOrderCode;
-- DON'T USE, JUST HERE TO DEMONSTRATE THE ISSUE OF NOT USING 'TYPE'
SELECT b.WorkOrderCode,
CreateUserName = STUFF((SELECT CONCAT(';', u.UserName)
FROM #User AS u
INNER JOIN #TrxIssueInventory AS i
ON i.ProfileOid = u.ProfileOid
WHERE i.WorkOrderCode = b.WorkOrderCode
FOR XML PATH('')
), 1, 1, '')
FROM #TrxIssueInventory AS B
GROUP BY b.WorkOrderCode

STUFF(
(
SELECT DISTINCT '; ' + CAST(CreateUserName AS VARCHAR (MAX))
FROM [PanatrackerGP].[dbo].[TrxIssueInventory]
WHERE (WorkOrderCode = A.WorkOrderCode)
FOR XML PATH ('')
),1,2,''
) AS [USERS]
FROM [PanatrackerGP].[dbo].[TrxIssueInventory] AS A
WHERE WorkOrderCode = 'S12119'
GROUP BY WorkOrderCode
------------------OUTPUT-----------------------
WorkOrderCode | USERS
S12119 | FO; lgm
Thank you all!

Related

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 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, 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];

Combine Static Columns with Dynamic Columns in SQL SERVER 2008

I have a table SchoolStudent with three columns and the following values
Now, for a student we can have dynamic columns which are stored in a table with values as:
I want a query where i can club static fields as well as dynamic fields in a single SQL Query. I tried using Pivot but was not successful. Please suggest on how to accomplish this. I am basically doing it so that on frontend i have one resultset which can be searched thru.
So query should be:
Select
StudentID, FirstName, Address, MotherName,
MotherEmail, MotherOccupation, Mother Salary,
FacebookProfileName, VehicleRegNo
from SchoolStudent
Inner Join
(Logic to convert rows to columns)
Since you have dynamic columns, then you will need to use dynamic SQL to generate the result that you want. This query will generate the list of columns in the second table and PIVOT them to then be joined to the SchoolStudent to get the other columns:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(DynamicColumnName)
from StudentDetails
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = '
select s.studentid,
s.firstname,
s.address,
d.*
from SchoolStudent s
inner join
(
SELECT studentId,' + #cols + '
from
(
select studentId, dynamiccolumnname,
dynamiccolumnvalue
from StudentDetails
) x
pivot
(
max(dynamiccolumnvalue)
for dynamiccolumnname in (' + #cols + ')
) p
) d
on s.StudentId = d.StudentId'
execute(#query);
See SQL Fiddle with Demo. This query gives the result:
| STUDENTID | FIRSTNAME | ADDRESS | FACEBOOK PROFILE NAME | MOTHER EMAIL | MOTHER NAME | MOTHER OCCUPATION | MOTHER SALARY | VEHICLE REG NO |
-----------------------------------------------------------------------------------------------------------------------------------------------
| 4 | admin | efewfwfew | ross | ram#ram.com | ram#ram.com | ram#ram.com | ram#ram.com | UP 14 as |
You could use sub query format like this:
SELECT t1.StudentID,
t1.FirstName,
t1.Address,
(SELECT t2.DynamicColumnValue FROM table2 t2 WHERE t2.StudentID = t1.StudentID AND t2.DynamicColumnName = 'Mother Name') AS 'MotherName',
(SELECT t2.DynamicColumnValue FROM table2 t2 WHERE t2.StudentID = t1.StudentID AND t2.DynamicColumnName = 'Mother Email') AS 'MotherEmail'
FROM Table1 t1
or you could use inner join format like this:
SELECT t1.StudentID,
t1.FirstName,
t1.Address,
t2.DynamicColumnValue AS 'MotherName'
t3.DynamicColumnValue AS 'MotherEmail'
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.StudentID = t2.StudentID AND t2.DynamicColumnName = 'Mother Name'
INNER JOIN Table2 t3 ON t1.StudentID = t3.StudentID AND t2.DynamicColumnName = 'Mother Email'
With some dynamic sql, you can do this:
DECLARE #cols NVARCHAR(2000)
SELECT #cols = STUFF((SELECT DISTINCT '],[' + DynamicColumnName FROM DynamicValues ORDER BY '],[' + DynamicColumnName FOR XML PATH('')), 1, 2, '') + ']'
DECLARE #query NVARCHAR(4000);
SET #query = N'select s.StudentID, s.FirstName, s.Address,'+#cols+' from SchoolStudent s
join
(
select * from DynamicValues
pivot (Max(DynamicColumnValue) for DynamicColumnName in ('+#cols+')) as pvt
) as b on b.StudentID=s.StudentID'
EXECUTE(#query)

SQL query to split a column based on hardcoded values

I have a table eg assume this setup
table MyTable has various columns Id, UserId, col1, col2 col3 including column called Stuff.
I want to output certain Columns from MyTable with a query
but i want to split the 'Stuff' column such that 2 new columns are shown in the query
I can define the categories hardcoded, im not sure how this can be represented in sql
Categoy1 = "alpha, bravo, delta, gamma';
Categoy2 = "charlie, echo, hotel';
MyTable
ID | UserID | Stuff | Other Cols....
----------------------------------------------------------
1 1 alpha
2 2 hotel
3 1 charlie
4 1 echo
5 1 gamma
6 2 bravo
7 2 delta
i want the select query to show
UserId | Category1 | Catergory2
----------------------------------------------------------
1 alpha, gamma charlie, echo
---------------------------------------------------------
2 bravo, delta hotel
----------------------------------------------------------
i.e produce 2 columns split based on whether the stuff column contains an item from category1 or category2
based on a distinct userId the categories content can be comma separated as hown above
Please can you show how this can be done
Hope this makes sense.
Thanks
You can use the xml extensions to concatenate your strings, then just hard code the categories into each subquery:
CREATE TABLE #T (ID INT, UserID INT, [Stuff] VARCHAR(300))
INSERT #T VALUES
(1, 1, 'alpha'),
(2, 2, 'hotel'),
(3, 1, 'charlie'),
(4, 1, 'echo'),
(5, 1, 'gamma'),
(6, 2, 'bravo'),
(7, 2, 'delta');
SELECT UserID,
[Category1] = STUFF(( SELECT ', ' + [Stuff]
FROM #T t2
WHERE [Stuff] IN ('alpha', 'bravo', 'delta', 'gamma')
AND t.UserID = t2.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, ''),
[Category2] = STUFF(( SELECT ', ' + [Stuff]
FROM #T t2
WHERE [Stuff] IN ('charlie', 'echo', 'hotel')
AND t.UserID = t2.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM ( SELECT DISTINCT UserID
FROM #T
) t
Example on SQL Fiddle
You could define your categories at the start in a CTE (Categories) for improved readibility:
WITH Categories AS
( SELECT Category, Name
FROM (VALUES
(1, 'alpha'),
(1, 'bravo'),
(1, 'delta'),
(1, 'gamma'),
(2, 'charlie'),
(2, 'echo'),
(2, 'hotel')
) t (Category, Name)
), Data AS
( SELECT UserID, [Stuff], Category
FROM T
INNER JOIN Categories c
ON c.Name = T.[Stuff]
)
SELECT UserID,
[Category1] = STUFF(( SELECT ', ' + [Stuff]
FROM Data t2
WHERE Category = 1
AND t.UserID = t2.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, ''),
[Category2] = STUFF(( SELECT ', ' + [Stuff]
FROM Data t2
WHERE Category = 2
AND t.UserID = t2.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM ( SELECT DISTINCT UserID
FROM T
) t
Example on SQL Fiddle
My try, the technique I learned from Stack Overflow!... Please check:
DECLARE #Categoy1 NVARCHAR(MAX) = 'alpha, bravo, delta, gamma',
#Categoy2 NVARCHAR(MAX) = 'charlie, echo, hotel'
SELECT
UserID,
STUFF((SELECT ', ' + display_term
FROM sys.dm_fts_parser('"'+ ',' + #Categoy1 + '"', 1033, NULL, 0) INNER JOIN
YourTable T on display_term=[Stuff]
WHERE T.UserID= x.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '') Category1,
STUFF((SELECT ', ' + display_term
FROM sys.dm_fts_parser('"'+ ',' + #Categoy2 + '"', 1033, NULL, 0) INNER JOIN
YourTable T on display_term=[Stuff]
WHERE T.UserID= x.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '') Category2
FROM YourTable x
GROUP BY UserID