SQL PIVOT to generate required output - sql

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

Related

Pivot multiple rows in initial table

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)

Dynamic Pivot SQL Server Not Showing Value

I have the following table:
oCode oDateTime oValue
---------------------------------------------
A 2017-01-01 10
B 2017-01-01 20
C 2017-01-01 5
I want to have the following result:
oDateTime A B C
------------------------------------------------
2017-01-01 10 20 5
If Static Pivot, I would use the following code:
select
*
from
(
select
sTag
, sDateTime
, sValue
from #condesarsp
) src
pivot
(
sum(sValue)
for sTag in ([X1], [X2], [X3])
) piv
order by sDateTime;
But unluckily, The oValue is not shown. Its just showing null value. Is there a typo on the code above?
After, I want to have dynamic pivot. So I don't need to define the column, It's just generate from oCode value.
Need help, thank you.
First, you would required to specify max() function rather than sum() and other sTag has value should be [A], [B], [C] rather than [X1]..[X3]
select *
from
(
select
oCode, oDateTime, oValue
from table
) src pivot(
max(oValue)
for ocode in ([A], [B], [C])
) piv
order by 1;
Ya there is some mistakes in your query. You have to give the oCode like A,B,C instead of [X1], [X2], [X3]. Like this:
for sTag in (A, B, C)
So the corrected code is:
select
*
from
(
select
oCode
, oDateTime
, oValue
from condesarsp
) src
pivot
(
sum(oValue)
for oCode in (A, B, C) -- This line is changed.
) piv
order by oDateTime;
Follow the link for demo:
http://sqlfiddle.com/#!18/06a9d/3
Dynamic Query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.oCode)
FROM condesarsp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT oDateTime, ' + #cols + ' from
(
select oCode
,oDateTime
,oValue
from condesarsp
) x
pivot
(
sum(oValue)
for oCode in (' + #cols + ')
) p '
execute(#query);
Follow the link to the demo:
http://sqlfiddle.com/#!18/06a9d/7

converting and concatenating multiple rows into columns

I am using Dynamic PIVOT approach to convert the dynamic rows into columns and its working fine for me. But I have one more requirement on top of it. I am using below query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ','
+ QUOTENAME(case when d.col = 'STN_CODE' then col+'_'+cast(seq as varchar(10))
else col+'_'+cast(seq as varchar(10)) end)
from ( select row_number() over(partition by POF_FILE_ID,
PART_PFX,
PART_BASE,PART_SFX
order by STN_CODE,PROCESS_ELEMENT) seq
from APT_POINT_OF_FIT
) t
cross apply
(
select 'STN_CODE', 1 union all
select 'PROCESS_ELEMENT', 2
) d (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT POF_FILE_ID,PART_PFX,PART_BASE,PART_SFX, ' +
#cols + '
from
(
select t.POF_FILE_ID,t.PART_PFX,t.PART_BASE,t.PART_SFX,
col = case
when c.col = ''STN_CODE'' then col+''_''+cast(seq as varchar(10))
else col+''_''+cast(seq as varchar(10))
end,
value
from
(
select POF_FILE_ID,PART_PFX,PART_BASE,PART_SFX,STN_CODE,
PROCESS_ELEMENT,
row_number() over(partition by POF_FILE_ID,
PART_PFX,
PART_BASE,
PART_SFX
order by STN_CODE) seq
from APT_POINT_OF_FIT
) t
cross apply
(
select ''STN_CODE'', STN_CODE union all
select ''PROCESS_ELEMENT'', PROCESS_ELEMENT
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
My requirement is to insert the values in separate columns till seq 8 and concatenate all other column values coming after that seq(> seq8).
Any help would be appreciated.
Thanks!

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

SQL Pivot table returning NULL for non-existent child table values

I have a typical RDMS setup where records in a main table can have optional records in a related table via a M2M join. I'm trying to PIVOT this data but in cases where there is no relation I want to return a default value. The join I have below is returning NULL.
select *
from
(
SELECT s.Biz_Name, la.Name AS Association, ISNULL(i.Location, 'Default') as Location
FROM dbo.ShopAssociations sa
INNER JOIN dbo.LookupAssociations la
ON sa.AssociationID = la.AssociationID
RIGHT JOIN dbo.Basic_Shop_Info s
ON sa.ShopID = s.ShopID
INNER JOIN dbo.Images i
ON la.ImageID = i.ImageID
) DataTable
PIVOT
(
min(Location)
for association in
([OnCall],[OCGuy],[ASCLogo],[ASC_OtherSt],[ASE],[AASP],[AASP_PA],
[ASE_BlueSeal],[AAA],[AAA-B],[ASA],[ATRA],[ICAR],[CAA],[ACDelco],
[Cert],[ASC],[BBB],[Goodyear],[Limos],[RVs],[Bosch],[NARSA],
[DiscTire],[BigO],[Tires],[Firestone],[ASCCA],[JustTires],[ASE_Blue])
) PivotTable
The output looks like this:
BizName OnCall OCGuy ASCLogo ASC_OtherSt ASE ...
"Wonderful Biz" somevalue somevalue NULL somevalue NULL
What I am trying to achieve is if a child record doesn't exist in INNER JOIN from Basic_Shop_Info to ShopAssociations that we get "Default" instead of NULL. I've tried ISNULL(), Coalesce() and even a CASE statement, all with the same results.
Based on your comment it sounds like you found a solution. I am only answering this to provide a suggestion based on the fact you are pivoting so many columns and they are all hard-coded. You can use dynamic SQL for a PIVOT and your query would look something like this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsPivot AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Name)
from dbo.LookupAssociations
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsPivot = STUFF((SELECT distinct ', IsNull(' + QUOTENAME(Name) +', ''Default'')'
from dbo.LookupAssociations
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Bizname, ' + #colsPivot + ' from
(
SELECT s.Biz_Name, la.Name AS Association, ISNULL(i.Location, ''Default'') as Location
FROM dbo.ShopAssociations sa
INNER JOIN dbo.LookupAssociations la
ON sa.AssociationID = la.AssociationID
RIGHT JOIN dbo.Basic_Shop_Info s
ON sa.ShopID = s.ShopID
INNER JOIN dbo.Images i
ON la.ImageID = i.ImageID
) x
pivot
(
min(Location)
for association in (' + #cols + ')
) p
'
execute(#query)
The value #colsPivot is adding the IsNull() around each of you columns so you can put in place the Default value. But this should provide the same result as your original query where everything was hard-coded.
This will get the list of columns at run-time so then you do not have to hard-code anything and it will accept new values without having to change the query.
I got this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(c.col+cast(rn as varchar(10)))
from
(
select row_number() over(partition by person_nbr
order by person_nbr,first_name, last_name, medication_name) rn
from TA_PIVOT
) d
cross apply
(
select 'diag' col, 1 sort
) c
group by col, rn, sort
order by rn, sort
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT person_nbr, first_name, last_name,medication_name,' + #cols + '
from
(
select person_nbr,first_name,last_name,medication_name,
col+cast(rn as varchar(10)) col,
value
from
(
-- when you perform an unpivot the datatypes have to be the same.
-- you might have to cast the datatypes in this query
select person_nbr,first_name,last_name, medication_name, cast(icd_code_id as varchar(500)) diag,
row_number() over(partition by person_nbr order by person_nbr, first_name, last_name,medication_name) rn
from ta_pivot
) src
unpivot
(
value
for col in (diag)
) unpiv
) d
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);