Quick question that's bugging me.
When using PIVOT in T-SQL, can the 'FOR..IN' portion reference a table rather than a defined list of values?
Example, instead of something like:-
PIVOT (Count(widgets) For Team IN ([Dave],[Peter],[John]....etc))
Could you do something like:-
PIVOT (Count(widgets) for Team IN (SELECT TeamLeader FROM Teams))
I can find no reference to confirm whether or not this is possible.
No, this is not possible.
The PIVOT operator syntax dictates that these values is entered as a list:
...
IN ( [first pivoted column],
[second pivoted column],
...
...
[last pivoted column])
But you can do this dynamically, something like:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(Teamleader)
FROM Teams
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = ' SELECT ' + #cols +
' FROM AnotherTable a
PIVOT
(
Count(widgets) For Team IN (' + #cols + ')' +
') p';
execute(#query);
Related
I want to declare a table variable and fill it from the pivot with dynamic column to perform join statement.
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols =
STUFF((SELECT DISTINCT ',' + QUOTENAME(ColName)
FROM [sbs].[ProposalAmounts]
GROUP BY ColName, ProposalID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #query = N'SELECT ProposalID, ' + #cols + N' from
(select ProposalID, Amount, ColName from [sbs].[ProposalAmounts]) x
PIVOT
(MAX(Amount)for ColName in (' + #cols + N')) p '
EXEC sp_executesql #query;
This is what I've done so far and I'm confused as to how to declare a table variable that has dynamic columns in it.
This is the result of the query above:
And this is the result of the table I want to perform join statement:
Like Jeroen Mostert commented, you need to make everything dynamic.
I would suggest to put the join inside the dynamic query. Instead of a table variable, I use a common table expression.
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SELECT #cols =
STUFF((SELECT DISTINCT N', ' + QUOTENAME([ColName])
FROM [_tmp_].[ProposalAmounts]
GROUP BY [ColName], [ProposalID]
FOR XML PATH(N''), TYPE).value(N'.', N'NVARCHAR(MAX)'), 1, 2, N'')
SET #query = N'
WITH [CTE_Pivoted_ProposalAmounts] AS
(
SELECT [ProposalID], ' + #cols + N'
FROM
(SELECT [ProposalID], [Amount], [ColName] FROM [sbs].[ProposalAmounts]) x
PIVOT (MAX([Amount]) FOR [ColName] IN (' + #cols + N')) p
)
SELECT *
FROM
[sbs].[OtherTable] ot
INNER JOIN [CTE_Pivoted_ProposalAmounts] ppa ON ppa.[ProposalID] = ot.[ProposalID];
';
EXEC sp_executesql #query;
You need to replace [sbs].[OtherTable] with the actual name of the table you want to join with. And you might also tweak the join criteria and the fields in the SELECT clause. This code here is just a simple example. I assume you will manage to fix the query yourself to make it behave as you expect.
Trying to create a view with a PIVOT in it, can't figure out the syntax. The source view has three columns: ClientNameID, Item, and CountOfItem. I want ClientNameID to be the row, Item to be the column, and CountOfItem to be the value.
I figured it out:
SELECT clientnameid
FROM dbo.vAggregateSalesByCustomerAndItem
pivot (
Sum(countOfItem) FOR Item in ([Ring])
) PivotTable
The problem was syntax BUT I also learned that the dimensions (columns) must be hard-coded in the DML. I wanted to get the dimensions dynamically from a table, which is do-able in Excel, with a column range, but not here.
I think you should try this. its worked for you..
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + Item
from dbo.vAggregateSalesByCustomerAndItem
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT clientnameid ' + #cols + ' from
(
select clientnameid,countOfItem,Item
from dbo.vAggregateSalesByCustomerAndItem
) x
pivot
(
Sum(countOfItem)
for Item in (' + #cols + ')
) p '
execute(#query);
SSMS is highlighting that something is wrong on the line FOR urlsByFilm.Media_Type_ID IN...
BEGIN
SELECT urlsByFilm.Film_ID, urlsByFilm.Media_Type_ID, urlsByFilm.Media_File_Name
FROM [dbo].[Film_Media_Item] urlsByFilm
PIVOT
(
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN (SELECT DISTINCT Media_Type_ID FROM [dbo].[Film_Media_Item])
) AS pivot
WHERE API_ID in (#API_IDs)
END
I cannot run this, can you help?
you can't have SQL expression in the IN clause, you need to specify the values.
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN
(SELECT DISTINCT Media_Type_ID FROM [dbo].[Film_Media_Item])
You need to use dynamic SQL to achieve what you are doing.
your query would like this, with dynamic SQL
DECLARE #cols NVARCHAR(2000)
SELECT #cols = STUFF(( SELECT DISTINCT
'],[' + Media_Type_ID
[dbo].[Film_Media_Item]
ORDER BY '],[' + Media_Type_ID
FOR XML PATH('')
), 1, 2, '') + ']'
DECLARE #query NVARCHAR(4000)
SET #query = N'SELECT Media_File_Name, '+
#cols +'
FROM
(SELECT urlsByFilm.Film_ID, urlsByFilm.Media_Type_ID, urlsByFilm.Media_File_Name
FROM [dbo].[Film_Media_Item] urlsByFilm)p
PIVOT
(
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN ( '+
#cols +' )
) AS pvt
WHERE API_ID in (#API_IDs)'
EXECUTE(#query)
I am trying to pivot table DYNAMICALLY but couldn't get the desired result.
Here is the code to create a table
create table Report
(
deck char(3),
Jib_in float,
rev int,
rev_insight int,
jib_out float,
creation int
)
insert into Report values
('A_1',0.345,0,0,1.23,20140212),
('B_2',0.456,0,4,2.34,20140215),
('C_3',0.554,0,6,0.45,20140217),
('D_4',0.231,0,8,7.98,20140222),
('E_5',0.453,0,0,5.67,20140219),
('F_6',0.344,0,3,7.23,20140223)'
Code written so far.... this pivots the column deck and jib_in into rows but thats it only TWO ROWS i.e the one i put inside aggregate function under PIVOT function and one i put inside QUOTENAME()
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(deck)
FROM (SELECT p.deck FROM dbo.report AS p
GROUP BY p.deck) AS x;
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.deck, p.jib_in
FROM dbo.report AS p
) AS j
PIVOT
(
SUM(jib_in) FOR deck IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
I need all the columns to be pivoted and show on the pivoted table. any help would be appreciated. I am very new at dynamic pivot. I tried so many ways to add other columns but no avail!!
I know there are other ways please feel free to mention if there is any other way to get this right.
Please use this (If you are getting Collation issue, please change all the 3 INT datatypes):
STATIC code:
SELECT HEADER, [A_1],[B_2],[C_3],[D_4],[E_5],[F_6]
FROM
(SELECT DECK,HEADER, VALUE FROM REPORT
UNPIVOT
(
VALUE FOR HEADER IN ([JIB_IN],[REV],[REV_INSIGHT],[JIB_OUT],[CREATION])
) UNPIV
) SRC
PIVOT
(
SUM(VALUE)
FOR DECK IN ([A_1],[B_2],[C_3],[D_4],[E_5],[F_6])
) PIV
Using Dynamic SQL:
DECLARE #COLSUNPIVOT AS NVARCHAR(MAX),
#QUERY AS NVARCHAR(MAX),
#COLSPIVOT AS NVARCHAR(MAX)
SELECT #COLSUNPIVOT = STUFF((SELECT ','+QUOTENAME(C.NAME)
FROM SYS.COLUMNS AS C
WHERE C.OBJECT_ID = OBJECT_ID('REPORT') AND C.NAME <> 'DECK'
FOR XML PATH('')), 1, 1, '')
SELECT #COLSPIVOT = STUFF((SELECT ',' + QUOTENAME(DECK)
FROM REPORT T FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #QUERY
= 'SELECT HEADER, '+#COLSPIVOT+'
FROM
(
SELECT DECK,HEADER,VALUE FROM REPORT
UNPIVOT
(
VALUE FOR HEADER IN ('+#COLSUNPIVOT+')
) UNPIV
) SRC
PIVOT
(
SUM(VALUE)
FOR DECK IN ('+#COLSPIVOT+')
) PIV'
EXEC(#QUERY)
This question already has answers here:
Get ROWS as COLUMNS (SQL Server dynamic PIVOT query)
(2 answers)
Closed 9 years ago.
I have the following basic SQL statement which uses the PIVOT command.
SELECT *
FROM
(
--select statement that creates my dataset
) s
PIVOT (Max(incidentcount) for dept in ([dept1],[dept2])) p
This does what I expect it to do, it gives me a count of incidents per reason with depts as my columns. My problem is the departments that I am using for my columns go from 1-60.
Is there anyway I can tell the query to use the column Department to populate the PIVOT in part. Obviously I want to avoid manually typing each department.
EDIT
This is the sql that creates my dataset that I use in the pivot...
SELECT Details, Department , count(*) NoIncidents
FROM myincidentdb
Group by Details, Department
EDIT 2
You will want to use dynamic sql to PIVOT this, your code will be similar to this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(dept)
from yourtablewithDepartments
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *
from
(
<your query goes here>
) src
pivot
(
max(incidentcount)
for dept in (' + #cols + ')
) piv '
execute(#query)
If you post more details like table structure, etc then this can be refined to meet your needs.
Edit, based on your current query, it looks like you can use the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(department)
from myincidentdb
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Details, ' + #cols + '
from
(
select Details, Department
from myincidentdb
) x
pivot
(
count(Department)
for Department in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo