I have to write a dynamic pivot based on a complex query and I want to use a common table expression to create the dataset on which I have to build the pivot to keep it outside the dynamic sql and have it compiled
My problem is that I don't know if i can use the CTE in a SET where I wrap the dynamic SQL I have to execute.
let see the code:
WITH DatiCTE AS
(
SELECT ...
)
SET #DynamicPivotQuery =
N'SELECT IdActivity, ' + #PivotSelectColumnNames + '
FROM DatiCTE
PIVOT(SUM(NumOfDays)
FOR Area IN (' + #PivotColumnNames + ')) AS PVTTable'
WHERE 1 = 1
EXEC sp_executesql #DynamicPivotQuery
This way i get an error near SET #DynamicPivotQuery =
If I replace SET with a SELECT the stored procedure is compiled but if i run it I get:
Invalid object name 'DatiCTE'
Move the definition of the CTE WITH DatiCTE AS to be inside the dynamic sql like this:
SET #DynamicPivotQuery =
N'WITH DatiCTE AS
(
SELECT ...
)
SELECT IdActivity, ' + #PivotSelectColumnNames + '
FROM DatiCTE
PIVOT(SUM(NumOfDays)
FOR Area IN (' + #PivotColumnNames + ')) AS PVTTable'
+ 'WHERE 1 = 1';
EXEC sp_executesql #DynamicPivotQuery;
for now i switch to temp table:
SELECT ...
INTO #TempTable
SET #DynamicPivotQuery =
N'
SELECT IdActivity, ' + #PivotSelectColumnNames + '
FROM #TempTable
PIVOT(SUM(NumOfDays)
FOR Area IN (' + #PivotColumnNames + ')) AS PVTTable'
+ 'WHERE 1 = 1';
EXEC sp_executesql #DynamicPivotQuery;
but i have soume doubt about concurrent users. i try table variable but cant be used in dynamic sql...
Related
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
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
I have some bulk views to create for an entire database.
To create a view the general syntax is as follows:
CREATE VIEW [TABLE_NAME]
AS
SELECT [COLUMN1], [COLUMN2], [COLUMN3], [COLUMN4]
FROM [TABLE_NAME]
WITH CHECK OPTION;
I would like to set the column names in the script above by querying the column names ([COLULMN1], [COLUMN2], etc) from INFORMATION_SCHEMA.COLUMNS.
Is there a way to achieve this by table name?
COALESCE is your friend good programmer. What you want to do is get a csv list of COLUMNS. Then using dynamic sql you can auto generate the rest of the code.
declare #columns AS VARCHAR(MAX)
SELECT #COLUMNS = NULL
select #COLUMNS = coalesce(#columns+',','')+c.name from syscolumns as c
inner join sysobjects as o on c.id = o.id
WHERE O.NAME = 'change me to your table name'
SELECT #COLUMNS
SELECT ' CREATE VIEW ' + 'COOL VIEW NAME' + ' AS ' +
' SELECT ' + #COLUMNS +
' FROM '+ ' change me to your table name '+
' WITH CHECK OPTION;'
EDIT
I purposely didn't declare the view anywhere. If you want to declare the view just execute the scripts like so. BUT YOU SHOULD NEVER just execute code on your servers without reading it all I purposely excluded the execution part as I think it is bad judgement just to cut and paste code and execute it without understanding/testing.
DECLARE #sql varchar(max)
SELECT #sql = ' CREATE VIEW ' + 'COOL VIEW NAME' + ' AS ' +
' SELECT ' + #COLUMNS +
' FROM '+ ' change me to your table name '+
' WITH CHECK OPTION;'
EXEC(#sql);
Here's one option... replace "MyTableName" with the table name you want, or wrap it in a cursor that reads TABLE_NAME from INFORMATION_SCHEMA.VIEWS into #tableName:
DECLARE #tableName sysname;
DECLARE #sql nvarchar(max);
DECLARE #columnList nvarchar(max);
SELECT #tableName = 'MyTableName';
SELECT #columnList = '';
SELECT #columnList += CASE WHEN LEN(#columnList) = 0 THEN '' ELSE ', ' END + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tableName ORDER BY ORDINAL_POSITION;
SELECT #sql = 'CREATE VIEW [TABLE_NAME] AS
SELECT ' + #columnList + '
FROM [' + #tableName + ']
WITH CHECK OPTION;'
PRINT #sql
EXEC(#sql);
I have the following query:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(MaxDate)
FROM (SELECT DISTINCT MaxDate FROM CustPeriodTable) AS MaxDates
SET #DynamicPivotQuery =
N'SELECT ' + #ColumnName + ' AS Test, min(rn)
FROM CustPeriodTable '
EXEC sp_executesql #DynamicPivotQuery
I'm getting an invalid column name error for every entry in #ColumnName. I'm in the process of setting up a more complicated query that will involve a pivot but I'm trying to get this chunk working first. Can anyone point out where this problem might be coming from?
For these types of issues you need to look at what the dynamic query is. Instead of executing it just select it.
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(MaxDate)
FROM (SELECT DISTINCT MaxDate FROM CustPeriodTable) AS MaxDates
SET #DynamicPivotQuery =
N'SELECT ' + #ColumnName + ' AS Test, min(rn)
FROM CustPeriodTable '
SELECT #DynamicPivotQuery
-- EXEC sp_executesql #DynamicPivotQuery
From here you should be able to determine what the issue is.
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.