SQL pivot transform - sql

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.

Related

Convert Rows to Columns SQL

I am trying to convert rows to columns in SQL server. I am trying to convert the value's a product gets while being tested during quality. I have tried the pivot function but having trouble doing so as the same values do get repeated and it can not be easily sorted into rows. The table I am trying to pivot holds ~30K data row's so hoping to find a dynamic solution for this.
The maximum number of new columns is 30 but sometimes a product doesn't get tested as much so it can be less. The new column would be based off my inspection_unit_number field. Is this possible to achieve in SQL
Current data
What I hope to achieve
Current Attempt
SELECT BATCH , characteristic, [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30]
from
(
select inspection_lot ,node_number ,characteristic ,inspector ,inspection_unit_number ,start_date ,measured_value ,original_value ,material_no ,batch
from stg.IQC_Tensile_TF
) d
pivot
(
max(measured_value)
for
INSPECTION_UNIT_NUMBER in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30])
) piv;
You will have to go for a dynamic query, check if this will suit your needs.
I created a common table expression to be able to use distinct and then order by in the stuff function:
DECLARE #QUERY NVARCHAR(MAX)
DECLARE #Columns NVARCHAR(MAX)
WITH cte_unique_inspection_unit_number AS
(
SELECT DISTINCT QUOTENAME('TestResults' + CAST(inspection_unit_number AS VARCHAR)) TestResultsN,
inspection_unit_number
FROM IQC_Tensile_TF
)
SELECT #Columns = STUFF((SELECT ', ' + TestResultsN
FROM cte_unique_inspection_unit_number
ORDER BY inspection_unit_number
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,''),
#query = 'SELECT batch, node_number, characteristic, ' + #Columns + ' from
(
select batch,
node_number,
characteristic,
measured_value,
''TestResults'' + CAST(inspection_unit_number AS VARCHAR) TestResultsN
from IQC_Tensile_TF
) x
pivot
(
max(measured_value)
for TestResultsN in (' + #Columns + ')
) p '
EXEC(#query)
To view the execution in fiddle:
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=7898422e4422faacb25d7f3c2285f14a
If you find my answer useful, i would appreciate if you vote up and mark as accepted =D

Dynamic Pivot Table by Month

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>;

Struggling with SQL Pivot Query Syntax

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.

SQL Query for report

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

MS SQL Server pivot table with subquery in column clause

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