Dynamic SQL Query contains extra rows - sql

I have a dynamic SQL Query that is providing the correct data but I have extra rows appearing, I'm not sure why. Query is this
-- Nuke the temp DB if it already exists
IF OBJECT_ID('tempdb..##TBL_TEMP') IS NOT NULL
DROP TABLE ##TBL_TEMP
--Parameter to hold dynamically created SQL Script
declare #sqlquery as nvarchar(max)
--Parameter to hold the Pivoted Column Values
declare #pivotcolumns as nvarchar(max)
--generate list of territories that will become column names
select #pivotcolumns = coalesce(#pivotcolumns + ',','') + quotename(Territory)
from
(SELECT DISTINCT TERRITORY FROM LiveGAPDetailedBudget
where res_id = '160') AS X
--select #pivotcolumns
--create dynamic query with all values for pivot at runtime
set #sqlquery = 'SELECT [ProductCategory] AS "Product Category",' + #pivotcolumns +' INTO ##TBL_TEMP
FROM LiveGAPDetailedBudget
PIVOT (MAX([Budget])
FOR [Territory] IN (' + #pivotcolumns +')) AS T WHERE res_id = 160'
--select #sqlquery
--Execute Dynamic Query
EXEC sp_executesql #sqlquery
--View results in temp table
SELECT * FROM ##TBL_TEMP order by [Product Category]
The output from the query is linked - I can't for the life of me get these rows consolidated to eliminate nulls....see link below

You are selecting extra columns that you are not required for pivoting.
change your query to
set #sqlquery = 'SELECT [ProductCategory] AS "Product Category",'
+ #pivotcolumns
+ ' INTO ##TBL_TEMP
FROM (
SELECT [ProductCategory], [Territory], [Budget]
FROM LiveGAPDetailedBudget
WHERE res_id = 160
) AS D
PIVOT (MAX([Budget])
FOR [Territory] IN (' + #pivotcolumns +')) AS T '

Related

Is there any way to create View or temp table from dynamic SQL query

I have a query that provides some data I want to save this data in a temp table or view. Please help
The query is given below:
IF OBJECT_ID('tempdb..#NLSPMTS3_tmp') IS NOT NULL
DROP TABLE #NLSPMTS3_tmp
SELECT *
INTO #NLSPMTS3_tmp
FROM vwNLSPayments4
DECLARE #Columns AS VARCHAR(MAX)
SELECT #Columns = COALESCE(#Columns + ', ','') + QUOTENAME(b.mop_fpd)
FROM (SELECT DISTINCT mop_fpd FROM #NLSPMTS3_tmp) AS B
ORDER BY B.mop_fpd
-- You can't remove nulls from a PIVOT, so you have to create a second set of column names
DECLARE #NullColumns as VARCHAR(MAX)
SELECT #NullColumns =
COALESCE(#NullColumns + ', ','') + 'ISNULL(' + QUOTENAME(b.mop_fpd) + ', 0) ' + QUOTENAME(b.mop_fpd)
FROM (Select DISTINCT mop_fpd FROM #NLSPMTS3_tmp) AS B
ORDER BY B.mop_fpd
DECLARE #SQL as NVARCHAR(MAX)
SET #SQL = 'SELECT acctrefno, ' + #NullColumns + '
FROM
(SELECT payment_amount, acctrefno, mop_fpd
FROM
nlsdev.dbo.vwnlsPayments2
) as PivotData
PIVOT
(sum(payment_amount) FOR mop_fpd IN (' + #Columns + ')) AS PivotResult ORDER BY acctrefno'
EXEC (#SQL)
I just simply put create a view as <above SQL query> but it did not work.

SQL Select from an array

Is there an easy way to select from a (long) array?
I want something like this
SELECT citizenship, count(1)
FROM table
WHERE year(date) = 2018
GROUP BY citizenship
But I want all citizenship as column and all dates (from 2000 until as 2018) as rows so I can delete the where clause.
Sounds like you want to use PIVOT columns.
Heres what I think you want... ( in SQL Server)
See this article: https://www.databasejournal.com/features/mssql/converting-rows-to-columns-pivot-and-columns-to-rows-unpivot-in-sql-server.html
Applied to you that could be...
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME([citizenship])
FROM (SELECT DISTINCT [citizenship] FROM [dbo].[table]) AS PivotExample
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT [Year], ' + #PivotColumns + '
FROM (SELECT [citizenship], YEAR([Date]) AS [Year], COUNT(1) As Counter
FROM [Table] GROUP BY [citizenship], YEAR([Date])) AS A
PIVOT( SUM(Counter)
FOR [citizenship] IN (' + #PivotColumns + ')) AS P'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery
Adding distinct will give you list of unique citizens
SELECT distinct citizenship
FROM table
WHERE year(date) >= 2000 and year(date) <= 2018

Pivot join with two columns having varchar datatype in SQL Server 2012

I need to use pivot to create time table from the following data:
I'm using this query
select
start_time, end_time, s.subj_name, tt.dd
from
time_table tt
inner join
subj s on tt.subjid = s.subjid
I am able to pivot my result to
I used following SQL code to do that:
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns = COALESCE(#PivotColumns + ',','') + QUOTENAME(dd)
FROM (SELECT DISTINCT(dd)
FROM time_table tt
WHERE divid = 1 AND tt.active = 1) AS PivotExample
SELECT #PivotColumns
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT start_time,end_time, ' + #PivotColumns + '
FROM [dbo].[time_table]
PIVOT( SUM(subjid)
FOR dd IN (' + #PivotColumns + ')) AS P'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery
Do help me out to get subjectname as value instead of subjectid
Since you are pivoting a VARCHAR, you can't use SUM, but have to use MAX or MIN
Try instead:
SET #SQLQuery =
N'SELECT start_time,end_time, ' + #PivotColumns + '
FROM [dbo].[time_table]
PIVOT( MAX(subjectname)
FOR dd IN (' + #PivotColumns + ')) AS P'
Found answer for it which provides simpler way to get it.
click to get answer

Dynamic pivoting SQL Server 2012

I am making attempts to run my first dynamic pivot in SQL Server 2012.
My #temp table that I am using for the dynamic pivoting looks like this.
YearMonth Agreement nr Discount
------------------------------------
201303 123 1
201303 12 0
201304 1 0
I am running this code and it does not work:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName = ISNULL(#ColumnName + ',', '') + QUOTENAME(YearMonth )
FROM (SELECT DISTINCT YearMonth FROM #FINAL) AS Courses
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT [Agreement nr],YearMonth , ' + #ColumnName + '
FROM #FINAL
PIVOT(
COUNT(agreement nr)
FOR YearMonth IN (' + #ColumnName + ') AS PVTTable'
--Execute the Dynamic Pivot Query
EXECUTE #DynamicPivotQuery;
The error message I am getting is
FOR YearMonth IN ([201403]) AS PVTTable' is not a valid identifier.
What am I missing here?
The cause of the error is that you're missing a parenthesis before you alias the Pivot. More than this however your pivot was rather inefficient.
You should select what you need for the source table in your pivot otherwise it could run for a long time and produce a lot of rows with null returns.
The below is fixed and hopefully more efficient:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(YearMonth )
FROM (SELECT DISTINCT YearMonth FROM #FINAL) AS Courses
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT ' + #ColumnName + '
FROM (Select [Agreement nr], YearMonth from #FINAL) src
PIVOT(
COUNT([Agreement nr])
FOR YearMonth IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXECUTE sp_executesql #DynamicPivotQuery;
You forgot to close pivot.
PIVOT(
COUNT(Kundavtalid)
FOR YearMonth IN (' + #ColumnName + ')
) AS PVTTable' -- here you miss pathernesis
You are missing a parenthesis
SET #DynamicPivotQuery =
N'SELECT [Agreement nr],YearMonth , ' + #ColumnName + '
FROM #FINAL
PIVOT(
COUNT([agreement nr])
FOR YearMonth IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query

Dynamic SQL Result INTO Temporary Table

I need to store dynamic sql result into a temporary table #Temp.
Dynamic SQL Query result is from a pivot result, so number of columns varies(Not fixed).
SET #Sql = N'SELECT ' + #Cols + ' FROM
(
SELECT ResourceKey, ResourceValue
FROM LocaleStringResources where StateId ='
+ LTRIM(RTRIM(#StateID)) + ' AND FormId =' + LTRIM(RTRIM(#FormID))
+ ' AND CultureCode =''' + LTRIM(RTRIM(#CultureCode)) + '''
) x
pivot
(
max(ResourceValue)
for ResourceKey IN (' + #Cols + ')
) p ;'
--#Cols => Column Names which varies in number
Now I have to insert dynamic sql result to #Temp Table and use this #Temp Table with another existing table to perform joins or something else.
(#Temp table should exist there to perform operations with other existing tables)
How can I Insert dynamic SQL query result To a Temporary table?
Thanks
Can you please try the below query.
SET #Sql = N'SELECT ' + #Cols + '
into ##TempTable
FROM
(
SELECT ResourceKey, ResourceValue
FROM LocaleStringResources where StateId ='
+ LTRIM(RTRIM(#StateID)) + ' AND FormId =' + LTRIM(RTRIM(#FormID))
+ ' AND CultureCode =''' + LTRIM(RTRIM(#CultureCode)) + '''
) x
pivot
(
max(ResourceValue)
for ResourceKey IN (' + #Cols + ')
) p ;'
You can then use the ##TempTable for further operations.
However, do not forget to drop the ##TempTable at the end of your query as it will give you error if you run the query again as it is a Global Temporary Table
As was answered in (https://social.msdn.microsoft.com/Forums/sqlserver/en-US/144f0812-b3a2-4197-91bc-f1515e7de4b9/not-able-to-create-hash-table-inside-stored-proc-through-execute-spexecutesql-strquery?forum=sqldatabaseengine),
you need to create a #Temp table in advance:
CREATE TABLE #Temp(columns definition);
It seems that the task is impossible, if you know nothing about the dynamic list of columns in advance. But, most likely you do know something.
You do know the types of dynamic columns, because they come from PIVOT. Most likely, you know the maximum possible number of dynamic columns. Even if you don't, SQL Server has a limit of 1024 columns per (nonwide) table and there is a limit of 8060 bytes per row (http://msdn.microsoft.com/en-us/library/ms143432.aspx). So, you can create a #Temp table in advance with maximum possible number of columns and use only some of them (make all your columns NULLable).
So, CREATE TABLE will look like this (instead of int use your type):
CREATE TABLE #Temp(c1 int NULL, c2 int NULL, c3 int NULL, ..., c1024 int NULL);
Yes, column names in #Temp will not be the same as in #Cols. It should be OK for your processing.
You have a list of columns in your #Cols variable. You somehow make this list of columns in some external code, so when #Cols is generated you know how many columns there are. At this moment you should be able to generate a second list of columns that matches the definition of #Temp. Something like:
#TempCols = N'c1, c2, c3, c4, c5';
The number of columns in #TempCols should be the same as the number of columns in #Cols. Then your dynamic SQL would look like this (I have added INSERT INTO #Temp (#TempCols) in front of your code):
SET #Sql = N'INSERT INTO #Temp (' + #TempCols + N') SELECT ' + #Cols + N' FROM
(
SELECT ResourceKey, ResourceValue
FROM LocaleStringResources where StateId ='
+ LTRIM(RTRIM(#StateID)) + ' AND FormId =' + LTRIM(RTRIM(#FormID))
+ ' AND CultureCode =''' + LTRIM(RTRIM(#CultureCode)) + '''
) x
pivot
(
max(ResourceValue)
for ResourceKey IN (' + #Cols + ')
) p ;'
Then you execute your dynamic SQL:
EXEC (#Sql) OR sp_executesql #Sql
And then do other processing using the #Temp table and temp column names c1, c2, c3, ...
MSDN says:
A local temporary table created in a stored procedure is dropped
automatically when the stored procedure is finished.
You can also DROP the #Temp table explicitly, like this:
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp'
All this T-SQL code (CREATE TABLE, EXEC, ...your custom processing..., DROP TABLE) would naturally be inside the stored procedure.
Alternative to create a temporary table is to use the subquery
select t1.name,t1.lastname from(select * from table)t1.
where "select * from table" is your dyanmic query. which will return result which you can use as temp table t1 as given in example .
IF OBJECT_ID('tempdb..##TmepTable') IS NOT NULL DROP TABLE ##TmepTable
CREATE TABLE ##TmepTable (TmpCol CHAR(1))
DECLARE #SQL NVARCHAR(max) =' IF OBJECT_ID(''tempdb..##TmepTable'') IS NOT
NULL DROP TABLE ##TmepTable
SELECT * INTO ##TmepTable from [MyTableName]'
EXEC sp_executesql #SQL
SELECT Alias.* FROM ##TmepTable as Alias
IF OBJECT_ID('tempdb..##TmepTable') IS NOT NULL DROP TABLE ##TmepTable
Here is step by step solution for your problem.
Check for your temporary tables if they exist, and delete them.
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
IF OBJECT_ID('tempdb..##abc') IS NOT NULL
DROP TABLE ##abc
Store your main query result in first temp table (this step is for simplicity and more readability).
SELECT *
INTO #temp
FROM (SELECT ResourceKey, ResourceValue
FROM LocaleStringResources
where StateId ='+ LTRIM(RTRIM(#StateID)) + ' AND FormId =' + LTRIM(RTRIM(#FormID))
+ ' AND CultureCode =' + LTRIM(RTRIM(#CultureCode)) + ') AS S
Write below query to create your pivot and store result in another temp table.
DECLARE #str NVARCHAR(1000)
DECLARE #sql NVARCHAR(1000)
SELECT #str = COALESCE(#str+',', '') + ResourceKey FROM #temp
SET #sql = N'select * into ##abc from (select ' + #str + ' from (SELECT ResourceKey, ResourceValue FROM #temp) as A
Pivot
(
max(ResourceValue)
for ResourceKey in (' + #str + ')
)as pvt) as B'
Execute below query to get the pivot result in your next temp table ##abc.
EXECUTE sp_executesql #sql
And now you can use ##abc as table where-ever you want like
select * from ##abc
Hope this will help you.