Insert query results into temp table - sql

I've recently learned from here how to do PIVOT in SQL, and I actually took an example from the other question on here. It works perfectly.
However, I want to perform additional joins, after the query, but I am unable to insert into temporary table the results of query? How may I do that?
Create table
CREATE TABLE yt
([Store] int, [Week] int, [xCount] int)
;
INSERT INTO yt
([Store], [Week], [xCount])
VALUES
(102, 1, 96),
(101, 1, 138),
(105, 1, 37),
(109, 1, 59),
(101, 2, 282),
(102, 2, 212),
(105, 2, 78),
(109, 2, 97),
(105, 3, 60),
(102, 3, 123),
(101, 3, 220),
(109, 3, 87);
Perform pivoting query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Week)
from yt
group by Week
order by Week
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT store,' + #cols + ' from
(
select store, week, xCount
from yt
) x
pivot
(
sum(xCount)
for week in (' + #cols + ')
) p '
execute(#query)
The result is
store 1 2 3
101 138 282 220
102 96 212 123
105 37 78 60
109 59 97 87
But Id like to have it in #temp table, and I tried placing INTO #temp before 'Execute Query' and before FROM statement within Query.
Any idea? I am aware of SELECT * INTO #temp FROM BlaBla but seems its diff with Queries.

You can create a global temp table dynamically
declare #tblName nvarchar(10)
set #tblName = N'##Temp' + cast(##spid as nvarchar(5))
declare #tblCreate nvarchar(max)
SET #tblCreate = N'create table ' + #tblName + ' ('
+ REPLACE(#cols,',',' int,') + N' int)'
EXECUTE sp_executesql #tblCreate
And then edit your #query to insert into the table.
set #query = 'INSERT INTO ' + #tblName + ' SELECT store,' + #cols + ' from
(
select store, week, xCount
from yt
) x
pivot
(
sum(xCount)
for week in (' + #cols + ')
) p;
drop table ' + #tblName
execute(#query)

The problem you're facing with select ... into #temp inside the execute is that the table gets created, but due to being in separate scope, it gets dropped immediately when the execute ends, so your procedure can't see it.
Your code will work, if you create the table before calling execute and just use insert into. You can check this in SQL Fiddle. This just causes the problem that if your query is dynamic, how to create the table so that it fits the query.
Trying to create logic where you dynamically adjust the number of columns in SQL is not simple to do, and really isn't something you should be doing. Better way would be to handle that in your presentation layer.

DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Week)
from yt
group by Week
order by Week
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT store,' + #cols + ' Into ##tempyt from
(
select store, week, xCount
from yt
) x
pivot
(
sum(xCount)
for week in (' + #cols + ')
) p '
DROP TABLE IF EXISTS ##tempyt;
execute(#query);
select * from TempDB.sys.##tempyt

Related

Convert rows to columns considering multiple columns

I have current base table:
and I need to convert it to this:
I already have a dynamic SQL in place which is giving me below result for the LTD values:
But I am not able to create dynamically the columns for the Aggregationname based on the columns LTD and BOY and set the post fix to the column name.
Find my SQL below:
create table #tempIE
(
AGGREGATIONNAME varchar(2),
LTD decimal,
BOY decimal,
MONTH int
)
insert into #tempIE values ('XX', 50, 45, 00)
insert into #tempIE values ('XX', 150, 145, 01)
insert into #tempIE values ('XX', 300, 295, 02)
insert into #tempIE values ('YY', 25, 20, 00)
insert into #tempIE values ('YY', 50, 45, 01)
insert into #tempIE values ('YY', 75, 70, 02)
insert into #tempIE values ('ZZ', 500, 495, 00)
insert into #tempIE values ('ZZ', 600, 595, 01)
insert into #tempIE values ('ZZ', 700, 695, 02)
SELECT *
FROM #tempIE
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AGGREGATIONNAME)
FROM #tempIE c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT MONTH, ' + #cols + ' INTO ##tempIEnew from
(
select AGGREGATIONNAME
, LTD
--, BOY
, MONTH
from #tempIE
) x
pivot
(
max(LTD)
for AGGREGATIONNAME in (' + #cols + ')
) p '
;
execute(#query)
SELECT *
FROM ##tempIEnew
drop table #tempIE
drop table ##tempIEnew
As I mentioned in the comments, I much more prefer using conditional aggregation rather than the PIVOT operator, it's so much easier to work with as it's not got restrictive syntax.
With conditional aggregation, you can easily achieve a static pivot with the following:
SELECT IE.[MONTH],
MAX(CASE IE.AGGREGATIONNAME WHEN 'XX' THEN IE.LTD END) AS XX_LTD,
MAX(CASE IE.AGGREGATIONNAME WHEN 'YY' THEN IE.LTD END) AS YY_LTD,
/* ... */
MAX(CASE IE.AGGREGATIONNAME WHEN 'ZZ' THEN IE.BOY END) AS ZZ_BPY
FROM #tempIE IE
GROUP BY IE.[MONTH];
For a dynamic pivot, then you could achieve this with the following.
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE #Delim nvarchar(3) = N',' + #CRLF
SELECT #SQL = N'SELECT IE.[MONTH],' + #CRLF +
STRING_AGG(N' MAX(CASE IE.AGGREGATIONNAME WHEN ' + QUOTENAME(IE.AGGREGATIONNAME,'''') + N' THEN IE.LTD END) AS ' + QUOTENAME(CONCAT(IE.AGGREGATIONNAME,'_LTD')),#Delim) WITHIN GROUP (ORDER BY IE.AGGREGATIONNAME) + N',' + #CRLF +
STRING_AGG(N' MAX(CASE IE.AGGREGATIONNAME WHEN ' + QUOTENAME(IE.AGGREGATIONNAME,'''') + N' THEN IE.BOY END) AS ' + QUOTENAME(CONCAT(IE.AGGREGATIONNAME,'_BOY')),#Delim) WITHIN GROUP (ORDER BY IE.AGGREGATIONNAME) + #CRLF +
N'FROM #tempIE IE' + #CRLF +
N'GROUP BY IE.[MONTH];'
FROM (SELECT DISTINCT AGGREGATIONNAME
FROM #tempIE) IE;
--PRINT #SQL;--Your best friend
EXEC sys.sp_executesql #SQL;
Note I assume you are using a fully supported version of SQL Server (as it's not noted you aren't) and so there's no need to FOR XML PATH and 2 passes of the table. I also switch to creating the query inline, as attempting to that with a variable #Columns is a real pain with conditional aggregation; I actually don't recommend that method either cause it's respective (like PIVOT).
db<>fiddle

how to create dynamic table

I have a dynamic pivoted query which generates a result set and I want to insert that data into a table. But the problem is columns are dropped or generated by the time. So by the time I cannot predict columns. That is why I created a dynamic pivoted dataset. So how to insert that data set into table?
One solution is to drop and recreate the table every time but I don't know how to do it. I tried CTE, TEMP table but EXEC support only select, insert, update, delete statement:
DECLARE #columns NVARCHAR(MAX), #sqlquery NVARCHAR(MAX), #orderby Nvarchar(MAX),#value Nvarchar(max);
SET #columns = N'';
SET #value=N'0'
SELECT #columns += N', ' + QUOTENAME([Note_Type])
FROM
(
SELECT distinct
No_T
FROM [DS_DM].[dbo].[DAILY_TABLE]
where No_T not in (570,80,150,590,80,99)
)as A order by No_T
SET #sqlquery = N'
Select
K._Number
,D.C_Number
,' + STUFF(#columns, 1, 2, '') + '
from
(
select
_Number
,' + STUFF(#columns, 1, 2, '') + '
from
(
select distinct
right(REPLICATE('+#value+',11) +_Number,11) as [_Number]
,No_t
,No_T_Des
FROM [DS_DM].[dbo].[DAILY_TABLE]
where No_T not in (570,80,150,590,80,99)
)AS J
pivot
(
count(No_T_Des) FOR [No_t] IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
)P
)K
left join
[DS_DM].[dbo].[D_TABLE] D on k._Number = D._Number
';
EXEC sp_executesql #sqlquery
I've modified your code to reflect my proposed solution.
IF OBJECT_ID (N'NEW_TABLE', N'U') IS NOT NULL
BEGIN
DROP TABLE NEW_TABLE
END
DECLARE #columns NVARCHAR(MAX), #sqlquery NVARCHAR(MAX), #orderby Nvarchar(MAX),#value Nvarchar(max);
SET #columns = N'';
SET #value=N'0'
SELECT #columns += N', ' + QUOTENAME([Note_Type])
FROM
(
SELECT distinct
No_T
FROM [DS_DM].[dbo].[DAILY_TABLE]
where No_T not in (570,80,150,590,80,99)
)as A order by No_T
SET #sqlquery = N'
Select
K._Number
,D.C_Number
,' + STUFF(#columns, 1, 2, '') + '
INTO NEW_TABLE
from
(
select
_Number
,' + STUFF(#columns, 1, 2, '') + '
from
(
select distinct
right(REPLICATE('+#value+',11) +_Number,11) as [_Number]
,No_t
,No_T_Des
FROM [DS_DM].[dbo].[DAILY_TABLE]
where No_T not in (570,80,150,590,80,99)
)AS J
pivot
(
count(No_T_Des) FOR [No_t] IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
)P
)K
left join
[DS_DM].[dbo].[D_TABLE] D on k._Number = D._Number
';
EXEC sp_executesql #sqlquery
So I found the answers to my questions.
there are 2 fileds which remais static every time. so I've created ETL that drop that table and recreate every single day with those two fileds. and rest of the 66 columns which are dynamic (drops or newly created) every day. so i've made a cursor for that which loop through all of that categories and altering that table that've created and added that code to ETL
So bassically Every single day that ETL Runs Drop the existing table, Create new table with the 2 static filds and altering same table using cursor with the dynamic filds.

How to pivot rows into colums dynamically SQL Server

I have a request which returns something like this:
--------------------------
Tool | Week | Value
--------------------------
Test | 20 | 3
Sense | 20 | 2
Test | 19 | 2
And I want my input to look like this:
-------------------------
Tool | W20 | W19
-------------------------
Test | 3 | 2
Sense | 2 | null
Basically, for every week I need to have a new column. The number of week and of tools is dynamic.
I have tried many things but nothing worked. Anybody have a solution ?
Try this
CREATE table #tst (
Tool varchar(50), [Week] int, Value int
)
insert #tst
values
('Test', 20, 3),
('Sense', 20,2),
('Test', 19, 2)
Here is the Dynamic Query:
DECLARE #col nvarchar(max), #query NVARCHAR(MAX)
SELECT #col = STUFF((SELECT DISTINCT ',' + QUOTENAME('W' + CAST([Week] as VARCHAR))
from #tst
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = '
SELECT *
FROM (
SELECT Tool,
Value,
''W'' + CAST([Week] as VARCHAR) AS WeekNo
FROM #tst
) t
PIVOT
(
MAX(t.Value)
FOR WeekNo IN (' + #col + ')
) pv
ORDER by Tool'
EXEC (#query)
Result
Tool W20 W19
=================
Sense 2 NULL
Test 3 2
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
( Tool varchar(5), Week int, Value int)
;
INSERT INTO #temp
( Tool , Week , Value )
VALUES
('Test', 20, 3),
('Sense', 20, 2),
('Test', 19, 2)
;
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max),
#col NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' +'w'+ tbl.[Week] + ']'
FROM (
SELECT DISTINCT CAST([Week] AS VARCHAR)[Week]
FROM #temp
) AS tbl
SELECT #statement = 'SELECT *
FROM
(
SELECT
Tool , ''w''+ CAST(Week AS VARCHAR) week , Value
FROM
#Temp
) src
PIVOT(MAX(Value)for Week in (' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
This is how I would do it ... If I understood your question correctly
if object_id('tempdb..#InputTool') is not null drop table #InputTool
create table #InputTool (Tool nvarchar(10), [20] int, [19] int)
insert into #InputTool (Tool, [20], [19])
values
('Test', 3, 2),
('Sense', 2, null)
declare #cols nvarchar(max)
select #cols = STUFF((SELECT ',' + QUOTENAME(name)
from tempdb.sys.columns
where object_id = object_id('tempdb..#InputTool')
and Column_id > 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #sqlquery nvarchar(max) =
'select Tool, Weeks, Value from (
select * from #InputTool
) as it
UNPIVOT
(
Value FOR Weeks IN (' + #cols + ')
) AS Weeks
order by Weeks desc'
execute (#sqlquery);
Give it a shot and let me know if it worked

Convert vertical sql result into horizontal output with Group by fields in MS SQL Server

I have a table( in SQL Server 2008) which has vertical sales transactions data, i would like to convert vertical output to horizontal output, i tried to use PIVOT, but some how not getting idea how to apply group by on PIVOT, as i want Sum based on AccountHeadID, TransType and IsPast Column.
Sample Table
CREATE TABLE Trans
([TransID] int,
[CustID] int,
[AccountHeadID] int,
[TransType] varchar(100),
[IsPast] bit,
[Amount] int)
;
INSERT INTO Trans
([TransID],CustID, [AccountHeadID], [TransType], [IsPast],[Amount])
VALUES
(1, 1, 1, 'Sales',1,1000),
(2, 1, 1, 'Sales',0,500),
(3, 1, 1, 'Sales',0,400),
(4, 1, 1, 'Return',0,300),
(5, 1, 1, 'Return',0,200),
(6, 1, 1, 'Return',0,100),
(7, 1, 1, 'Return',1,150),
(8, 1, 2, 'Sales',1,2000)
Current Query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(AccountHeadID)
from Trans
group by AccountHeadID
order by AccountHeadID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT CustID,' + #cols + '
from
(
SELECT
a.CustID,
a.AccountHeadID,
a.TransType,
a.Amount,
a.isPast
FROM Trans a
) x
pivot
(
sum(Amount)
for AccountHeadID in (' + #cols + ')
) p '
execute sp_executesql #query;
Expected Output
CustID | Account-HeadID-TransType-IsPast[1-Sales-Past] | Account-HeadID-TransType-IsCurrent[1-Sales-Current] | Account-HeadID-TransType-IsCurrent[1-Return-Past] | Account-HeadID-TransType-IsCurrent[1-Return-Current] | Account-HeadID-TransType-IsCurrent[2-Sales-Past]| ...
1 |1000 | 900 (500 + 400) |150 | 600[300+200+100] |2000
See SQL Fiddle with Demo
Any suggestion or input are most welcome!
Thanks
Suresh
Try this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(CONVERT(NVARCHAR(10),AccountHeadID) + N'-' + TransType + N'-' + CONVERT(NVARCHAR(10),IsPast))
from Trans
group by AccountHeadID, TransType, IsPast
order by AccountHeadID, TransType, IsPast
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--select #cols
set #query = 'SELECT CustID,' + #cols + '
from
(
SELECT
a.CustID,
CONVERT(NVARCHAR(10),AccountHeadID) + N''-'' + TransType + N''-'' + CONVERT(NVARCHAR(10),IsPast) Acct,
a.Amount
FROM Trans a
) x
pivot
(
sum(Amount)
for Acct in (' + #cols + ')
) p '
execute sp_executesql #query;
SQL Fiddle

Including default values on dynamic pivot

I am pivoting data in a table based on date, but need to return NULL for dates with no data.
Data in [dbo].[Metrics]:
The dynamic pivot SQL I am executing:
DECLARE #cols NVARCHAR(1000);
SELECT #cols =
STUFF((SELECT N'],[' + month_day
FROM (SELECT DISTINCT RIGHT(CONVERT(NCHAR(10), [Date], 126), 2)
FROM [Metrics]) AS O(month_day)
ORDER BY month_day
FOR XML PATH('')
), 1, 2, '') + N']';
DECLARE #sql NVARCHAR(2000);
SET #sql =
N'SELECT [Key], ' + #cols +
N' FROM (SELECT [Key], ' +
N' RIGHT(CONVERT(NCHAR(10), [Date], 126), 2) AS month_day, ' +
N' [Value] ' +
N' FROM [Metrics]) AS O ' +
N'PIVOT ' +
N'(SUM([Value]) FOR month_day IN (' + #cols + N')) AS P;';
EXECUTE(#sql);
...and the result set that dynamic SQL returns:
As you can see, since I do not have data for every day of the month it is simply not returning columns for those days. How can I have it return columns 10-23 and 28-31 with NULL for each cell? It should return columns 1-31 regardless of the actual month (e.g., 31 columns even when there are less than 31 days in a given month).
Any help is appreciated.
Then you don't really need that columns to be generated dynamically, since you always want them from 1 to 31. The easier way would be hardcoding those values on your pivot, really. Anyway, here is the way you can define your columns dynamically and still get all days:
SELECT #cols =
STUFF((SELECT N'],[' + CAST(number AS VARCHAR(2))
FROM (SELECT DISTINCT number
FROM master..[spt_values]
WHERE number BETWEEN 1 AND 31) AS O(number)
ORDER BY number
FOR XML PATH('')
), 1, 2, '') + N']';
And the version you really should be using is this:
SELECT *
FROM (SELECT [Key],
RIGHT(CONVERT(NCHAR(10), [Date], 126), 2) AS month_day,
[Value]
FROM [Metrics]) AS O
PIVOT (SUM([Value]) FOR month_day IN ([01],[02],[03],[04],[05],[06],[07],[08],[09],
[10],[11],[12],[13],[14],[15],[16],[17],[18],
[19],[20],[21],[22],[23],[24],[25],[26],[27],
[28],[29],[30],[31])) AS P;