Pivot multiple rows in initial table - sql

I have a table which i would like to pivot to show how many categories a person is affiliated with...
I would like to pivot this to show:
There are a lot more members and categories but the theory i believe should be the same.
I have attempted this however it only shows the first line for each.
Thanks in advance
Will

#Will, this is the logic you need. Basically a pivot function on the column of interest.
DECLARE #tbl TABLE (RegNo varchar(20), Category varchar(20), Number int)
INSERT INTO #tbl
SELECT 'R1050162', 'Gym', 1 UNION ALL
SELECT 'R1050162', 'Personal Trainer', 1 UNION ALL
SELECT 'R0093126', 'Group Exercise', 1 UNION ALL
SELECT 'R0143614', 'Yoga Teacher', 1
SELECT *
FROM
#tbl
PIVOT
(
SUM(Number)
FOR Category IN ([Gym], [Personal Trainer], [Group Exercise], [Yoga Teacher]
)
) AS PivotTable;
Output is below:

You need to use just sum the Number field in PIVOT function and for numerous categories get a category list:
DECLARE #categories AS NVARCHAR(MAX),
#your_query AS NVARCHAR(MAX);
select #categories = STUFF((SELECT distinct ',' + QUOTENAME(Category)
FROM your_table
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT RegNo, ' + #categories + ' from
(
SELECT RegNo, Category, Number FROM your_table) tab
PIVOT
(
SUM(Number)
FOR Category IN (' + #categories + ')
) p iv
ORDER BY piv.RegNo'
execute(#your_query)

Related

show results in a Pivot way (no aggregate)

i've searched all over for an answer for this, and couldn't really find anything useful,
im pretty much a begginer in Sql so maybe i'm missing something basic
i have a simple table with 2 columns : line, fullname
this is the query i use :
SELECT
(select distributionline from extrasums where key=accounts.accountkey and SuFID='63') as 'line',
fullname
FROM
accounts
ORDER BY
(select distributionline from extrasums where key=accounts.accountkey and SuFID='63'),
(select dotinline from extrasums where key=accounts.accountkey and SuFID='68')
these are the results i get : (not allowed to embed images)
basically i get the distribution lines and the costumers, and the tables is ordered by the dist.lines and the place in line of each costumer.
all i want to do is show these results in a pivot-table style
i tried "pivot" but i understand you cant pivot without aggregate, because thats the whole point of "pivot" in sql.
this is what i want to achieve :
basically the dist.lines are the column names and the results are orders in a pivot way
the dist.lines are not permanent, one day we can have 3 lines. the other we can have 10 lines. its dynamic based on the deliveries for tomorrow. obviously.
same with the costumers.
you're welcome:
DROP TABLE IF EXISTS #temp;
SELECT RANK() OVER (PARTITION BY a.LINE ORDER BY a.fullname) AS rownum, a.line, a.fullname
INTO #temp
FROM ( SELECT 43 AS line, 'Daniel' AS fullname
UNION ALL
SELECT 43 AS line, 'john' AS fullname
UNION ALL
SELECT 43 AS line, 'kenny' AS fullname
UNION ALL
SELECT 43 AS line, 'adam' AS fullname
UNION ALL
SELECT 55 AS line, 'james' AS fullname
UNION ALL
SELECT 55 AS line, 'jones' AS fullname
UNION ALL
SELECT 68 AS line, 'kelly' AS fullname) AS a;
DECLARE #cols AS NVARCHAR(MAX), #colname AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SET #colname = STUFF(( SELECT DISTINCT ',' + QUOTENAME(c.line)
FROM #temp AS c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
, 1
, 1
, '');
SET #cols = STUFF(( SELECT DISTINCT ',ISNULL(' + QUOTENAME(c.line) + ','''') AS '+QUOTENAME(c.line )
FROM #temp AS c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
, 1
, 1
, '');
PRINT #cols
PRINT #colname
SET #query =
N'SELECT rownum, ' + #cols
+ N' from
(
select rownum
, fullname
, line
from #temp
) x
pivot
(
max(fullname)
for line in (' + #colname + N')
) p ';
PRINT #query
EXECUTE (#query);
enter image description here

SQL PIVOT to generate required output

Please see the data below:
I am looking for a query that generates the following output:
I am experimenting with 'PIVOT', but have not yet achieved the desired outcome.
This should work:
SELECT ReviewType, DER, LEI, NOR, [NOT], LIN
FROM Src
PIVOT (SUM(Total) FOR OwningAgency IN (DER, LEI, NOR, [NOT], LIN)) P
Simple pivoting:
SELECT *
FROM YourTable
PIVOT (
MAX(Total) FOR OwningAgency IN ([DER],[LEI],[NOR],[NOT],[LIN])
) pvt
Another way:
SELECT ReviewType,
CASE WHEN OwningAgency = 'DER' THEN MAX(Total) END [DER],
CASE WHEN OwningAgency = 'LEI' THEN MAX(Total) END [LEI],
CASE WHEN OwningAgency = 'NOR' THEN MAX(Total) END [NOR],
CASE WHEN OwningAgency = 'NOT' THEN MAX(Total) END [NOT],
CASE WHEN OwningAgency = 'LIN' THEN MAX(Total) END [LIN]
FROM YourTable
GROUP BY ReviewType,OwningAgency
Use dynamic column collection to select PIVOT Data, because it gives you any new column value added in table, suppose after 2-3 days if new OwningAgency say for XYZ added in your table even that it show your new column in PIVOT result:
CREATE TABLE tblOwningAgency
(
OwningAgency VARCHAR(50),
ReviewType CHAR(1),
Total INT
)
INSERT INTO tblOwningAgency VALUES('DER','E',584)
,('LEI','S',84)
,('NOR','S',28148)
,('LIN','S',1261)
,('DER','T',6310)
,('NOR','T',5527)
,('NOT','T',35705)
,('LIN','E',606)
,('NOT','S',22978)
,('LEI','T',4283)
,('LIN','T',687)
,('LEI','E',431)
,('NOR','E',161)
,('NOT','E',842)
,('DER','S',1937)
,('XYZ','S',1937)
DECLARE #OwningAgency AS NVARCHAR(MAX),#Query AS NVARCHAR(MAX);
SET #OwningAgency = STUFF((SELECT distinct ',' + QUOTENAME(OwningAgency)
FROM tblOwningAgency c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #Query =
'SELECT ReviewType, ' + #OwningAgency + ' from
(
SELECT *
FROM tblOwningAgency
) x
pivot
(
SUM(Total)
FOR OwningAgency in (' + #OwningAgency + ')
) p '
EXECUTE(#query)
#OwningAgency : It will give you your column list on which you wants to apply SUM

Convert dynamic text data rows into multiple columns

I'm trying to convert my result table which consist of multiple rows into multiple columns. below are my sample result before and after:
Before:
After:
Got a some idea from here but still no luck.
Update 1:
select #cols = STUFF((select ',' + QUOTENAME(institution) + ',' + QUOTENAME(intstatus)
From #temp
group by refno,frmstatus
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
i have no idea how to insert each column into the pivot query
set #query = 'select refno, frmstatus,' + #cols + '
from (
select refno, frmstatus, institution, intstatus from #temp
) x
pivot
(
???????
)
Please try the below query:
CREATE TABLE #temp(refno nvarchar(20), firmstatus nvarchar(20), institution nvarchar(20), intstatus nvarchar(20), ranking int)
DECLARE #qu NVARCHAR(MAX), #pcol NVARCHAR(MAX)
INSERT INTO #temp
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY refno ORDER BY institution ASC) AS ranking
FROM temp
SELECT #pcol=
STUFF((
SELECT
DISTINCT N', Institution'+ CAST (ranking AS NVARCHAR(25)) +', '+ N'Intstatus'+ CAST (ranking AS NVARCHAR(25))
FROM #temp
FOR XML PATH('')),1,1,'')
SET #qu=N'SELECT refno, firmstatus,'+ #pcol +
N' FROM
(
select refno,firmstatus,ColData,colheader+ CAST(ranking as varchar) as colnames from
(select * from #temp)s
UNPIVOT
(ColData for colheader in ([institution], [intstatus])) up
)S
PIVOT
(MAX(ColData) FOR colnames IN ('+#pcol +N')) AS piv'
EXEC sp_executesql #qu -- execute the dynamic sql
DROP TABLE #temp -- remove the temp table
The temp table in above script was created like below
--create table temp( refno nvarchar(20), firmstatus nvarchar(20), institution nvarchar(20), intstatus nvarchar(20))
--insert into temp values
--('AAA/1','Active','InstA','Ongoing'),
--('AAA/1','Active','InstB','Ongoing'),
--('AAA/1','Active','InstC','Ongoing'),
--('AAA/2','Active','InstA','Ongoing'),
--('AAA/2','Active','InstB','Ongoing')
Result received:
If repeated columns number is small and restricted, you can use simple solution:
WITH A AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY refno, fmstatus ORDER BY institution) n
FROM myTable
),
B AS (
SELECT refno, fmstatus,
CASE WHEN n=1 THEN institution END institution,
CASE WHEN n=1 THEN intstatus END intstatus,
CASE WHEN n=2 THEN institution END institution1,
CASE WHEN n=2 THEN intstatus END intstatus1,
CASE WHEN n=3 THEN institution END institution2,
CASE WHEN n=3 THEN intstatus END intstatus2
FROM A
)
SELECT refno, fmstatus,
MAX(institution) institution,
MAX(intstatus) intstatus,
MAX(institution1) institution1,
MAX(intstatus1) intstatus1,
MAX(institution2) institution2,
MAX(intstatus2) intstatus2
FROM B
GROUP BY refno, fmstatus
Otherwise use PIVOT

Adding a WHERE statement refering another table in Dynamic SQL

I currently have the following script which is pivoting results from rows into columns. It works a Great, apart from two issues;
I have a flag in another table which I want to filter by (basically: WHERE Table.Stats=YES). I'd normally do this in a basic query with an inner join followed by that WHERE statement. In the query below, I already have a WHERE FileSeq=25, which works, but this criteria I need to get working is calling on a different table.
The query is returning a lot of uncessary NULL fields.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(col+CAST(rn AS varchar(6)))
FROM
(
SELECT row_number() over(partition by UID ORDER BY ClassCode) rn
FROM dbo.StudentClasses
) d
CROSS APPLY
(
SELECT 'ClassCode', 1
) c (col, so)
GROUP BY col, rn, so
ORDER BY rn, so
FOR XML PATH(''), TYPE
).VALUE('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT UID,' + #cols + '
FROM
(
SELECT UID, col+CAST(rn AS varchar(10)) col, VALUE
FROM
(
SELECT UID, classcode,
row_number() over(partition by UID ORDER BY classcode) rn
FROM StudentClasses WHERE FileSeq=25
) t
CROSS APPLY
(
SELECT ''classcode'', CAST(classcode AS varchar(6))
) c (col, VALUE)
) x
PIVOT
(
MAX(VALUE)
for col in (' + #cols + ')
) p '
EXECUTE(#query)
Any assistance appreciated

Splitting a string of unlimited length SQL

I have a data column with values like this:
Table1
ID|GROUPNAME |MEMBER
1|GRP1_ML_Unit1_Role1|GRP=User1,DC=com;GRP=User2,DC=com
2|GRP2_ML_Unit2_Role2|GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com
3|GRP3_ML_Unit3_Role3|GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com
Expected output
ID|GRP1 |GRP2|GRP3 |GRP4 |MEM1 |MEM2 |MEM3 |MEM4|MEM5|
1 |GRP1 |ML |Unit1|Role1|GRP=User1,DC=com|GRP=User2,DC=com| | |
2 |GRP2 |ML |Unit2|Role2|GRP=User3,DC=com|GRP=User4,DC=com|GRP=User5,DC=com| |
3 |GRP3 |ML |Unit3|Role3|GRP=User6,DC=com|GRP=User7,DC=com|GRP=User8,DC=com|GRP=User8,DC=com |
Thanks,
Ryl
The completed solution is below with the sample data you gave me.
First, create a temp table and fill it with data.
-- Drop the table
drop table #member;
go
-- Sample table
create table #member
(
member_id int not null,
group_name varchar(256),
member_data varchar(8000)
);
go
-- Sample data
insert into #member values
(1, 'GRP1_ML_Unit1_Role1', 'GRP=User1,DC=com;GRP=User2,DC=com'),
(2, 'GRP2_ML_Unit2_Role2', 'GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com'),
(3, 'GRP3_ML_Unit3_Role3', 'GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com');
go
-- Show the data
select * from #member;
go
Second, copy down one of the many string splitters out there. I ended up installing Jeff Moden's string spliter for 8K max strings.
The query is almost there. However, each column we want is a row. We need to dynamically pivot the table.
--
-- Almost there!
--
-- Data in columns, instead of rows
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
go
Last but not least, figure out the number of columns. Write dynamic TSQL to pivot our dat and get our result.
--
-- Write dynamic sql to solve
--
DECLARE
#cols AS nvarchar(MAX),
#query AS nvarchar(MAX);
-- Get a dynamic number of columns
SET #cols = STUFF(
(
SELECT distinct ',' + QUOTENAME(c.cols_name)
FROM
(
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
) as c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
print #cols;
-- Make dynamic pivot query
set #query = 'SELECT member_id as ID1, group_name as GROUP1, ' + #cols + ' from
(
select m.member_id, m.group_name, s.Item as cols_data, ''MEM'' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data, '';'') s
) x
pivot
(
max(cols_data)
for cols_name in (' + #cols + ')
) p ';
execute(#query)
A screen shot of the results in the desired format.