Dynamic Pivot with column names from dynamic tables - sql-server

I am working on a project with SSRS and Rockwell Software's RSView32. Basically this software project logs manufacturing data to individual tables as such:
One table (Machine1_TagTable) has Tag names which describe the data as such: TagName, TagIndex. The name provides a human-understandable reference to the information contained in a second table. Example : Part Number, 1
The second table (Machine1_FloatTable) contains raw data with nothing more than a timestamp, TagIndex and value.
Example : 2013-12-10 15:44:11.322, 1, 12345(value)
I have a dynamic pivot which works for ONE table; however, I would like to use a variable parameter passed from SSRS to select both the TagTable and FloatTable.
This works with the Machine1_FloatTable as part of the dynamic statement, but not in the XML path building. I understand this is a scope issue, so I'm looking for creative ways to allow me to pass the table names from SSRS into this stored procedure.
Here's what I have now:
DECLARE #FLOATTABLE NVARCHAR(MAX), #TAGTABLE NVARCHAR(MAX), #startdate NVARCHAR(MAX),
#enddate NVARCHAR(MAX), #cols as NVARCHAR(MAX), #query as NVARCHAR(MAX)
SET #TAGTABLE ='dbo.Machine1_TagTable'
SET #FLOATTABLE = 'dbo.Machine1_FloatTable'
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(CONVERT(VARCHAR,TagName),'"')
FROM #tagtable
FOR XML PATH('')),1,1,'')
Set #query = 'SELECT DISTINCT DateAndTime, Millitm, ' + #cols + ' FROM ( select
T.DateAndTime, T.Millitm, N.TagName, T.Val from ' + #FLOATTABLE + ' T LEFT JOIN ' +
#TAGTABLE + ' N ON T.TagIndex=N.TagIndex WHERE T.DateAndTime Between '''+ #startdate +
''' AND '''+ #enddate +''') x PIVOT (MAX(Val) for TagName IN (' + #cols + ')) p'
PRINT (#query)
Any help or suggestions would be greatly appreciated. Thanks!

Well, it's possible, if I understand your question. You have to build a dynamic SQL string, and execute that to populate #cols.
declare #string nvarchar(MAX)
set #String = 'SELECT STUFF((SELECT DISTINCT '','' + QUOTENAME(CONVERT(VARCHAR,ActualDate),'
+ '''"'') FROM ' + #TAGTABLE + ' FOR XML PATH ('''')),1,1,'''')'
EXECUTE sp_executeSQL #String, #Cols OUTPUT
print #cols
It's pretty hacky, but I think it should work.

Related

Get the column's data in procedure? [duplicate]

I have the following data output from my database
Observation 1 aug -2015
Improvement suggestion 1 dec -2015
Observation 1 dec -2015
Accident 2 jan -2016
Non Conformity 5 jan -2016
Observation 5 jan -2016
I've tried to figure out how to use PIVOT-table to make this work but cannot make it work. The date is dynamic depending on a date in the database. The output I am looking for is like below. Can someone please point me into right direction?
Look at the fiddle what I've tried so far I know it is using SUM right now, and that is not correct, but I cannot figure out what to use. http://sqlfiddle.com/#!3/0bd0c/4
PS. The data and the image are not related, so don't be fooled by the image. It is just an example
Is this what you were looking for:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(ColumnName)
from tempData
group by ColumnName, name
FOR XML PATH(''), Type
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT Name, ' + #cols + N' from
(
select Name, value, ColumnName
from tempData
) x
pivot
(
SUM(value)
for ColumnName in (' + #cols + N')
) p '
exec sp_executesql #query;
Changing this in your fiddle return the rows as you need it.
Try it like this:
DECLARE #cols AS NVARCHAR(MAX)=
STUFF(
(
SELECT DISTINCT ',[' + ColumnName + ']'
FROM tempData
FOR XML PATH('')
)
,1,1,'');
DECLARE #SqlCmd VARCHAR(MAX)=
'SELECT p.*
FROM
(
SELECT *
FROM tempData
) AS tbl
PIVOT
(
SUM(Value) FOR ColumnName IN(' + #cols +')
) AS p';
EXEC(#SqlCmd);

Unpivot all other columns

Im new to Stack overflow and SQL and I'm trying to replicate a function in Microsoft Power Query to use in SQL instead.
I know how to Unpivot and keep 1 Column in SQL and then had to reference all the other columns by name to make the unpivot.
Now I need to Keep 3 ID columns and Unpivot the rest of the columns
(This table has 355 columns right now and will change)
Can anyone help me with this?
This is the furthest I got (Thanks to RAV DBLearning on Youtube), but I cant seem to find a way to Convert the columns types to 1 type.
DECLARE
#SQLSTRING NVARCHAR(MAX),
#COLUMNLIST NVARCHAR(1000) = ''
SELECT
#COLUMNLIST = #COLUMNLIST + QUOTENAME(NAME) + ','
FROM
sys.columns
WHERE
OBJECT_ID = OBJECT_ID('xp.XPROPERTYVALUES') AND
--COLUMN_ID NOT IN(1,2,3)
COLUMN_ID IN(452,453,454)
SELECT
#COLUMNLIST = LEFT(#COLUMNLIST,LEN(#COLUMNLIST)-1)
SET
#SQLSTRING =
'
SELECT
upv.id,
upv.item_id,
upv.itemtype_id,
upv.X_Category,
upv.X_Values
FROM
xp.XPROPERTYVALUES
UNPIVOT
(
X_Values FOR X_Category
IN
(' + #COLUMNLIST + ')
) AS upv
'
PRINT
(#SQLSTRING)
EXECUTE
sp_executesql #SQLSTRING
It just needs a source query.
And you can re-use the calculated column list for that.
DECLARE #SQLSTRING NVARCHAR(MAX),
#COLUMNLIST NVARCHAR(MAX);
DECLARE #TABLENAME VARCHAR(30) = 'xp.XPROPERTYVALUES';
SELECT #COLUMNLIST = CONCAT(#COLUMNLIST + ', ', QUOTENAME(NAME))
FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID(#TABLENAME)
AND LOWER(NAME) NOT LIKE '%id';
SET #SQLSTRING = N'SELECT upv.id
, upv.item_id, upv.itemtype_id
, upv.X_Category, upv.X_Values
FROM
(
SELECT id, item_id, itemtype_id,
'+ #COLUMNLIST + N'
FROM '+ #TABLENAME +N'
) src
UNPIVOT
(
X_Values FOR X_Category IN (' + #COLUMNLIST + N')
) upv';
-- SELECT #SQLSTRING;
EXECUTE sp_executesql #SQLSTRING;
db<>fiddle here

Dynamic pivot with tweaks

I'm trying to solve experiment with some SQL pivoting. I have created a pivot by naming the columns, I am now trying to do it dynamically. From a few searches I have come up with the following code
USE [LMS]
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(Learning_Path_Title)
FROM (SELECT DISTINCT [Learning_Path_Title] FROM [dbo].[copy from]) AS Courses
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT Distinct [Userd], ' + #ColumnName + '
FROM [dbo].[copy from]
PIVOT(MAX([Learning_Path_Complete])
FOR [Learning_Path_Title] IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
My data is structured in the following way
I want the table to be displayed as below

Stored Procedure: Passing a parameter when using dynamic SQL for pivoting data

As the title suggests, I'm trying use dynamic SQL to get column names for a pivoted table - however, I also want to be able to pass a parameter to a variable called #assessments, but I just can't seem to get it to work. Below is the code I'm using, would appreciate if anyone could take a look and let me know where I'm going wrong. Thank you
create PROCEDURE [dbo].[spTestExamResults]
AS
BEGIN
DECLARE #SQL as NVARCHAR(MAX)
DECLARE #ColumnName as NVARCHAR(MAX)
DECLARE #assessment as NVARCHAR(50)
SET NOCOUNT ON;
--Get distinct values from pivot source
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(subjectname)
From (SELECT DISTINCT SubjectName From qryPupilNCTest) as p order by p.Subjectname
SET #SQL =
'select pupil,PupilName, year' + #ColumnName + '
FROM qrypupilnctest
Where assessment in (' + #assessment + ')
PIVOT (MAX(grade) for subjectname in (' +#ColumnName + ')) piv'
EXEC (#SQL)
END
In your case, #assessment is the local variable with out any initialization and handled in the operation. So it always have empty value only and you won't get any result from the stored procedure.
As per your post title, you can alter the stored procedure and pass the #assessment as parameter, so the WHERE assessment IN ( will have some valid data and you will receive some valid result.
ALTER PROCEDURE [dbo].[spTestExamResults]
(
#assessment NVARCHAR(50)
)
AS
BEGIN
DECLARE #SQL AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
-- DECLARE #assessment as NVARCHAR(50) -- Remove the #assessment from the local variable
SET NOCOUNT ON;
--Get distinct values from pivot source
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(subjectname)
FROM (SELECT DISTINCT SubjectName FROM qryPupilNCTest) AS p
ORDER BY p.Subjectname
SET #SQL = 'SELECT pupil, PupilName, year' + #ColumnName + '
FROM qrypupilnctest
WHERE assessment IN (' + #assessment + ')
PIVOT (MAX(grade) FOR subjectname IN (' + #ColumnName + ')) piv'
EXEC (#SQL)
END
So the execution call will be:
EXEC [dbo].[spTestExamResults] 'paramvalue1, paramvalue2'

TSQL Pivot Long List of Columns

I am looking to use pivot function to convert row values of a column into separate columns. There are 100+ distinct values in that column and hard-coding each and every single value in the 'for' clause of the pivot function would be very time consuming and not good from maintainability purposes. I was wondering if there is any easier way to tackle this problem?
Thanks
You can use Dynamic SQL in a PIVOT for this type of query. Dynamic SQL will get the list of the items that you want to transform on execution which prevents the need to hard-code each item:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.condition_id)
FROM t c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT memid, ' + #cols + ' from
(
select MemId, Condition_id, condition_result
from t
) x
pivot
(
sum(condition_result)
for condition_id in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
If you post a sample of data that you need to transform, then I can adjust my query to demonstrate.
I was trying to do this and had db2 Data like this.
id,MCD1,MCD2,MCD3,MCD4
1,4,5,4,3
2,6,7,8,9
3,3,6,2,6
4,2,5,8,4
5,3,4,5,6
I wrote this Dynamic SQL in TSQL
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',', COLUMN_NAME FROM my_db.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE 'PivotLonger' AND COLUMN_NAME like 'MCD%'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id, MCD, Value
from [my_db].[dbo].[PivotLonger]
UNPIVOT
(Value FOR MCD IN (' + #cols + ')) AS unpvt'
execute(#query)
Resulted in expanding the columns into a nice long table :)
id,MCD,Value
1,MCD1,4
1,MCD2,5
1,MCD3,4
1,MCD4,3
2,MCD1,6
2,MCD2,7
2,MCD3,8
2,MCD4,9
3,MCD1,3
3,MCD2,6
3,MCD3,2
3,MCD4,6
4,MCD1,2
4,MCD2,5
4,MCD3,8
4,MCD4,4
5,MCD1,3
5,MCD2,4
5,MCD3,5
5,MCD4,6

Resources