I'm trying to create a dynamic pivot table in SQL that will report based on month and year. I did a bunch of research and was able to come up with the below query:
declare #dynamic nvarchar(max),
#column nvarchar(max);
set #column = N'';
select #column += N'' + datename(month,incurdate) +' '+ datename(year,incurdate) + ','
from (select distinct a.incurdate from artable a) as Transpose
select #column = substring(#column,0,len(#column))
set #dynamic = 'select * from
(
select month, incurdate, dolamount
from artable join dolentry on month = period
) b
pivot(sum(dolamount) for incurdate in (' + #column + ')) as PivotTable'
execute sp_executesql #dynamic
I am able to print the #column variable successfully, but the problems happen when I try to set it in the #dynamic variable. The error message is 'Msg 102, Level 15, State 1, Line 6
Incorrect syntax near '1990'.' 1990 is the first year of the first pivoted column. Any help or tips are appreciated. Thanks!
You need to use QUOTENAME in the following code:
select #column += N'' + QUOTENAME(datename(month,incurdate) +' '+ datename(year,incurdate)) + ','
from (select distinct a.incurdate from artable a) as Transpose
in order to get output like this:
[col01], [col02], [col03], ... , [col04]
As you can see from the docs, the PIVOT syntax requires the pivoting columns to be wrapped in square brackets:
SELECT <non-pivoted column>,
[first pivoted column] AS <column name>,
[second pivoted column] AS <column name>,
...
[last pivoted column] AS <column name>
FROM
(<SELECT query that produces the data>)
AS <alias for the source query>
PIVOT
(
<aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
) AS <alias for the pivot table>
<optional ORDER BY clause>;
Related
I'm trying to do a pivot in SQL Server using a column with a lot of levels. Currently I'm doing a
select '[' + category_1 + '],', count(*)
from myTable
group by '[' + category_1 + '],'
and copying and pasting the output into the text editor.
I was wondering if it's possible to declare a variable and use that as the IN ([],[],[]) information in the pivot command. Has anyone been able to do that?
I think it would look something like this:
#factorLevels = (select '[' + category_1 + '],' from (select category_1, count(*) from myTable) t1)
SELECT *
FROM
(select category_1, item_count from myTable) as t1
PIVOT
(
SUM(item_count)
FOR category_1 IN (#factorLevels)
) as PivotTable;
If I'm understanding you correctly, I think I have a solution. You can use dynamic SQL for this.
You will need to set a variable that contains all the values for the field by which you want to pivot, and then assign the query itself into a variable and execute it to get results:
DECLARE
#values VARCHAR(50),
#querytext VARCHAR(MAX)
;
SET #values = (SELECT '('+(SELECT STUFF(( SELECT ',[' + category_1 +']' FROM
<your table> FOR XML PATH('')), 1, 1, '') )+')')
;
SELECT #querytext =
'SELECT *
FROM (
SELECT
<your fields>
FROM
<your table>
WHERE
<your criteria>
GROUP BY
<your grouping>
) AS Main
PIVOT (
SUM(item_count)
FOR [category_1] IN ' + #values + '
) AS PivotSum'
EXEC sp_executesql #querytext
I want to use a query to return columns transformed from row from table FloatNAR800 with pivot I have this code but doesn't work for me. Any idea ?
declare #nume_coloane as nvarchar(max),
#dynamic_pivot_query as nvarchar(max)
set #nume_coloane = STUFF ((select ',' + QUOTENAME(TagIndex)
from (select distinct TagIndex from FloatN2_NAR800) sub
order by TagIndex
for xml path(''), type ).value('.', 'nvarchar(max)')
set #dynamic_pivot_query = 'select DateAndTime,' + #nume_coloane +
'from
(select DateAndTime, TagIndex, Val
from FloatN2_NAR800) x
pivot'
When I want to create this query an error appears :
Incorrect syntax near the keyword 'SET'
but I don't know what I do wrong ...
You are missing code... The pivot statement dos not end with the Pivot key word.
You code then...
PIVOT
(
<aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
) AS <alias for the pivot table>
Take a look here: https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
I would advise you to get the Pivot working first, then make it into a dynamic sql.
Anyone tell me whats wrong with my SQL, having a hard time with this today. The error is:
Msg 156, Level 15, State 1, Line 11
Incorrect syntax near the keyword 'select'.
Msg 102, Level 15, State 1, Line 11
Incorrect syntax near ')'.
SELECT *
FROM (
SELECT
left(datename(month,TransactionDateTime),3) as [month], year(TransactionDateTime) as [year],
count(*) as Total
FROM quotations
) as s
PIVOT
(
SUM(Total)
FOR [year] IN (select distinct year(TransactionDateTime) from quotations)
) AS pivot
The shape I am after is... So years as column names then 12 rows for each month. Below is just to illustrate the shape
// var data = google.visualization.arrayToDataTable([
// ['Month', '2013', '2014', '2015'],
// ['Jan', 10, 30, 31],
// ['Feb', 11, 30, 32],
//]);
The syntax for pivot is as follows (From TechNet):
PIVOT
(
<aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column], ... [last pivoted column])
) AS <alias for the pivot table>
You can see that inside IN clause there should be column names enclosed in [] which can be a problem if the column names are dynamic. This problem can be easily solved by using dynamic SQL.
Here is an example:
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(year(TransactionDateTime))
FROM Quotations
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query =
'SELECT *
FROM (
SELECT
left(datename(month,TransactionDateTime),3) as [month], year(TransactionDateTime) as [year],
count(*) as Total
FROM quotations
) as s
PIVOT
(
SUM(Total)
FOR [year] IN (' + #cols + ')
) AS pivot'
EXECUTE(#query)
I don't know what your schema is so there may be a mistake with table/column names. If this doesn't help I can be more precise if you share your schema and a sample data.
The problem is with the following part of your query
(select distinct year(TransactionDateTime) from quotations)
You need to provide a static list of years inside the in clause.
I am working on a aggregate report and I have got so far with the data but I am unsure how to proceed from here. I get by with SQL but my skills are limited
I have the follow in a temp table
ID Count Action
2 23 Installed
2 12 Uninstalled
2 36 Unchanged
3 12 Installed
3 25 Unchanged
4 35 Installed
4 25 Unchanged
I want to convert this into this format
ID Installed Uninstalled Unchanged
2 23 12 36
3 12 0 36
4 35 0 25
I have no idea where to go or even how to start to achieve this and cannot find anything to point me in the right direction (Im sure its there somewhere)
Any help would be appriciated
Try this:
SELECT
ID,
MAX(CASE WHEN "Action" = 'Installed' THEN Count END) AS 'Installed',
MAX(CASE WHEN "Action" = 'Uninstalled ' THEN Count END) AS 'Uninstalled',
MAX(CASE WHEN "Action" = 'Unchanged' THEN Count END) AS 'Unchanged'
FROM Table
GROUP BY ID;
Or using the SQL Server PIVOT table operator like so:
SELECT *
FROM
(
SELECT * FROM table
)t
PIVOT
(
MAX("Count") FOR "Action" IN([Installed], [Uninstalled], [Unchanged])
) p
SQL Fiddle Demo for both
However, for unknown number of Actions, you will have to select them dynamically like so:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Action)
from Table1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET #query = 'SELECT ID, ' + #cols + ' from
(
SELECT * FROM Table1
) x
PIVOT
(
MAX(count)
FOR action IN (' + #cols + ')
) p ';
EXECUTE(#query);
SQL Fiddle Demo(Dynamic Version)
It's called a pivot
Here's the documentation about it
The syntax is
SELECT <non-pivoted column>,
[first pivoted column] AS <column name>,
[second pivoted column] AS <column name>,
...
[last pivoted column] AS <column name>
FROM
(<SELECT query that produces the data>)
AS <alias for the source query>
PIVOT
(
<aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
) AS <alias for the pivot table>
<optional ORDER BY clause>;
Pivots are good, but very slow at times. Try it without one.
SELECT ID
, SUM(CASE WHEN [Action] = 'Installed' THEN [Count] ELSE 0 END) AS Installed
, SUM(CASE WHEN [Action] = 'Uninstalled' THEN [Count] ELSE 0 END) AS Uninstalled
, SUM(CASE WHEN [Action] = 'Unchanged' THEN [Count] ELSE 0 END) AS Unchanged
FROM <table>
GROUP BY ID
Im sure this is a simple technique although I can't find an answer so far!
I have
TIMESTAMP | POINTNAME | VALUE
2012-10-10 16:00:00 AHU01 20
2012-10-10 16:00:00 AHU02 25
2012-10-10 16:00:15 AHU01 26
2012-10-10 16:00:15 AHU02 35
etc... ( for approx 800 POINTNAMES)
with many pointnames I dont want to list each one in the 'IN' clause of the pivot 'FOR'
(as syntax given below) definition but would like to use perhaps a subquery.
So what I would like is all the POINTNAME values as columns with A TIMESTAMP AND VALUE column, so I will get one TIMESTAMP value and many columns with each POINTNAME, there is only one value per POINTNAME PER TIMESTAMP so I don't need to aggregate anything so just choose max anyway?
Something like:
SELECT [TIMESTAMP] FROM ( SELECT * FROM POINT_TABLE)
PIVOT( Max[Value] FOR [POINTNAME] IN (SELECT DISTINCT [POINTNAME] FROM POINT_TABLE)
would produce-
TIMESTAMP AHU01 AHU02
2012-10-10 16:00:00 20 25
2012-10-10 16:15:00 26 35
I realise it is probably no this simple but hopefully you get what I'm trying to achieve?
PIVOT SYNTAX:
SELECT <non-pivoted column>,
[first pivoted column] AS <column name>,
[second pivoted column] AS <column name>,
...
[last pivoted column] AS <column name>
FROM
(<SELECT query that produces the data>)
AS <alias for the source query>
PIVOT
(
<aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
) AS <alias for the pivot table>
<optional ORDER BY clause>;
for dynamic number of columns you have to use dynamic SQL
declare
#cols nvarchar(max),
#stmt nvarchar(max)
select #cols = isnull(#cols + ', ', '') + '[' + T.POINTNAME + ']' from (select distinct POINTNAME from TABLE1) as T
select #stmt = '
select *
from TABLE1 as T
pivot
(
max(T.VALUE)
for T.POINTNAME in (' + #cols + ')
) as P'
exec sp_executesql #stmt = #stmt
SQL FIDDLE EXAMPLE