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
Related
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>;
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.
I have a table with 2 columns TimeStamp and ID in MS SQLSERVER
TimeStamp ID
2015-05-20 1
2015-05-20 2
2015-05-20 1
2015-05-21 1
2015-05-21 2
2015-05-21 2
2015-05-21 1
My requirement is to calculate number of records for every Id according to date.
Requirement:
Date No of records for Id=1 No. records for ID=2 Total
2015-05-20 2 1 3
2015-05-21 2 2 4
Please let me know how can i do this for other columns as well.
Thanks
Using Pivot - can look like this:
SELECT [TimeStamp], [1] AS [No of records for Id=1], [2] AS [No of records for Id=2], [1]+[2] AS Total
FROM dbo.YourTable
PIVOT
(
COUNT(ID) FOR ID IN ([1],[2])
) pvt
ORDER BY [TimeStamp]
For completion the Dynamic Way:
DECLARE #id_values NVARCHAR(MAX)
DECLARE #stmt NVARCHAR(MAX)
SET #id_values = ''
SET #stmt = ''
--Get List of ID's
SELECT #id_values = #id_values + ',[' + CAST(ID AS VARCHAR) + ']'
FROM dbo.YourTable
GROUP BY ID
SET #id_values = RIGHT(#id_values, LEN(#id_values)-1) --Remove Leading Comma
--Build PIVOT Statement
SET #stmt = 'SELECT [TimeStamp],' + #id_values + ','+ REPLACE(#id_values,',','+') + ' AS Total
FROM dbo.YourTable
PIVOT
(
COUNT(ID) FOR ID IN (' + #id_values + ')
) pvt
ORDER BY [TimeStamp]'
--Execute
EXEC sp_executesql #stmt
I've got your answer using subqueries:
SQLFIDDLE: http://sqlfiddle.com/#!3/8c28c/5
SELECT DISTINCT t1.myts,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts
AND t2.id = 1) AS id_1_count,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts
AND t2.id = 2) AS id_2_count,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts) AS total
FROM mytable t1
If you add an id here though you would need another subquery
I am trying to convert column to rows. I am beginner to PIVOT. Tried below code but error is coming as 'Error converting data type nvarchar to datetime.
The incorrect value "Tot_GPS_Cnt" is supplied in the PIVOT operator.'
CREATE TABLE #tbl_Res1
(
CallDate DATETIME,
Tot_GPS_Cnt INT,
Tot_GND_Cnt INT,
Per_Ratio NUMERIC(10,2)
)
INSERT INTO #tbl_Res1
SELECT '2015-04-24 00:00:00.000','40','26','65.00' UNION ALL
SELECT '2015-04-25 00:00:00.000','22','14','63.64' UNION ALL
SELECT'2015-04-26 00:00:00.000','27','21','77.78' UNION ALL
SELECT'2015-04-27 00:00:00.000','41','23','56.10'
Source Table
Desired Output
I have tried with below query bu failing. Please help. Thanks in advance
SELECT CallDate=col, Tot_GPS_Cnt, Tot_GND_Cnt, Per_Ratio
FROM
( select CallDate, col, value from #tbl_Res1
cross apply
(
SELECT 'Tot_GPS_Cnt',cast(Tot_GPS_Cnt as varchar(10)) UNION ALL
SELECT 'Tot_GND_Cnt', cast(Tot_GND_Cnt as varchar(10)) UNION ALL
SELECT 'Per_Ratio', cast(Per_Ratio as varchar(10))
) c (col,value)
) d
PIVOT
(
max(value) for CallDate in ([Tot_GPS_Cnt], [Tot_GND_Cnt], [Per_Ratio])
) as piv
The correct syntax for PIVOT is:
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>
Hence, you have to place date values not [Tot_GPS_Cnt], [Tot_GND_Cnt], [Per_Ratio] in place of pivoted columns:
SELECT CallDate=col, [2015-04-24], [2015-04-25], [2015-04-26], [2015-04-27]
FROM
( select CallDate, col, value from #tbl_Res1
cross apply
(
SELECT 'Tot_GPS_Cnt',cast(Tot_GPS_Cnt as varchar(10)) UNION ALL
SELECT 'Tot_GND_Cnt', cast(Tot_GND_Cnt as varchar(10)) UNION ALL
SELECT 'Per_Ratio', cast(Per_Ratio as varchar(10))
) c (col,value)
) d
PIVOT
(
max(value) for CallDate in ([2015-04-24], [2015-04-25], [2015-04-26], [2015-04-27])
) as piv
Thank you #Giorgos Betsos. I just made dynamic solution. Just wanted to share with all.
DECLARE #coldata VARCHAR(500);
DECLARE #sql VARCHAR(MAX);
SELECT #coldata = COALESCE(#coldata + '], [', '') + CONVERT(VARCHAR(10),calldate,110)
FROM #tbl_Res1;
SELECT #coldata = '[' + #coldata +']';
SELECT #coldata;
SET #sql = 'SELECT CallDate=col, ' + #coldata + '
FROM
( SELECT CallDate, col, value FROM #tbl_Res1
cross apply
(
SELECT ''Tot_GPS_Cnt'', CAST(Tot_GPS_Cnt as VARCHAR(10)) UNION ALL
SELECT ''Tot_GND_Cnt'', CAST(Tot_GND_Cnt as VARCHAR(10)) UNION ALL
SELECT ''Per_Ratio'', CAST(Per_Ratio as VARCHAR(10))
) c (col,value)
) d
PIVOT
(
MAX(value) FOR CallDate IN (' + #coldata + ')
) as piv'
SELECT #sql;
EXECUTE (#SQL);
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