I just wrote a script here but I have no idea how to save it as a view or a table. It is dynamically creating columns from rows
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME([Period])
FROM (SELECT p.Period FROM dbo.[refv_IRR3_Op_Rev] AS p
INNER JOIN [dbo].[refv_IRR3_Op_Rev] AS o
ON p.RMDF = o.RMDF
GROUP BY P.Period) AS x;
SET #sql = N'
SELECT [Region]
,[LAU]
,[RMDF]
, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT [Region]
,[LAU]
,[RMDF]
,[Period]
,[Net_Operating_Cashflow]
FROM [FTTx_Build].[dbo].[refv_IRR3_Op_Rev]
) AS j
PIVOT
(
SUM([Net_Operating_Cashflow]) FOR Period IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
How do I save it as a view or table?
short answer: you can't. However you can build a stored procedure from your code and call that when you need those results.
Related
Hello everyone and thanks in advance.
I have two tables that I need to merge using Pivot.
1)Table with list of users:
#Tbl_staff(UserId INT,
Name NVARCHAR(MAX),
Surname NVARCHAR(MAX),
Level NVARCHAR (MAX)
)
2) Table with users' actions:
#Tbl_acts(Day DATE,
UserIdfk INT,
WorkedHours NVARCHAR(MAX),
Absence NVARCHAR(MAX),
Festivity NVARCHAR(2)
)
Table 2 has a complete month for each ID and for each day the action recorded. (Hours worked, hours of absence and type of absence, if the day is a holiday)..
It can also be null if in the db there is no action for that person on that day.
I wrote my Pivot like this:
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME((cast(USERID AS VARCHAR(MAX)) + ' ' + NAME+ ' ' + SURNAME+' ' +(ISNULL (LEVEL,''))))
FROM (SELECT p.USERID,p.NAME,p.SURNAME,p.LEVEL FROM #TBL_STAFF AS p
INNER JOIN #TBL_ACTS AS o
ON p.USERID = o.USERIDFK
GROUP BY p.USERID,P.NAME,P.SURNAME,P.LEVEL) AS x;
SET #sql = N'
SELECT DAY,' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT DISTINCT o.DAY,IDU = CAST(p.USERID AS NVARCHAR(MAX)), o.WORKEDHOURS
FROM #TBL_STAFF AS p, #TBL_ACTS AS o
where p.USERID= o.USERIDFK
) AS j
PIVOT
(
MAX(WORKEDHOURS) FOR IDU IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p ORDER BY DAY;';
PRINT #sql;
EXEC sp_executesql #sql;
(Trying to show only the worked hours ... would be a good start)
It's the result: Column 'day' is ok(31 rows) and 'staff' too but it shows nothing inside it.
I have a query that pulls through a dynamic list of columns (ie the columns can change at any time) and pivots the data showing he Maximum InstalledDate for those columns. My question is however, how do I pull through more than one aggregation? I need to have the Max LocationCode, MakeCode and ModelCode for each PlaceRef too but am struggling to do this. Many thanks in advance.
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(Component )
FROM (SELECT p.Component FROM VwLocationComponentCurrent AS p
INNER JOIN VwLocationListEntriesCurrent AS o ON p.PlaceRef = o.PlaceRef
where o.LocationList = N'NEWBUILD'
GROUP BY p.Component) AS x;
SET #sql = N'
SELECT PlaceRef, Address1, StreetName, PostCode, Substatus, BuildingType, BuildDate, ' + STUFF(#columns , 1, 2, '') + '
FROM
(
SELECT
vwLocationCurrent.PlaceRef
,vwLocationCurrent.BuildDate
,vwLocationCurrent.SubStatus
,vwLocationCurrent.StreetName
,vwLocationCurrent.Address1
,vwLocationCurrent.Address2
,vwLocationCurrent.Address3
,vwLocationCurrent.PostCode
,VwLocationComponentCurrent.Component
,VwLocationComponentCurrent.SubLocationCode
,VwLocationComponentCurrent.InstalledDate
,VwLocationComponentCurrent.MakeCode
,VwLocationComponentCurrent.ModelCode
,VwLocationListEntriesCurrent.LocationList
,vwLocationCurrent.BuildingType
FROM
vwLocationCurrent
INNER JOIN VwLocationListEntriesCurrent
ON vwLocationCurrent.PlaceRef = VwLocationListEntriesCurrent.PlaceRef
LEFT OUTER JOIN VwLocationComponentCurrent
ON vwLocationCurrent.PlaceRef = VwLocationComponentCurrent.PlaceRef
WHERE
VwLocationListEntriesCurrent.LocationList = ''NEWBUILD''
) AS j
PIVOT
(
MAX(InstalledDate) FOR Component IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;'
;
PRINT #sql;
EXEC sp_executesql #sql;
I suggest you don't use the "pivot" feature here, instead use an older technique employing "conditional aggregates". This means the creation of the "columns" string is more complex but it does allow you to output multiple aggregations in a single query. The following code is untested as there is no sample data to work with:
DECLARE #columns nvarchar(max)
, #sql nvarchar(max);
SET #columns = N'';
SELECT
#columns +=
+ N', max(case when Component = p.' + QUOTENAME(Component) + N' then SubLocationCode end) as ' + QUOTENAME('Loc_' + Component)
+ N', max(case when Component = p.' + QUOTENAME(Component) + N' then MakeCode end) as ' + QUOTENAME('Mak_' + Component)
+ N', max(case when Component = p.' + QUOTENAME(Component) + N' then ModelCode end) as '+ QUOTENAME('Mod_' + Component)
FROM (
SELECT
p.Component
FROM VwLocationComponentCurrent AS p
INNER JOIN VwLocationListEntriesCurrent AS o ON p.PlaceRef = o.PlaceRef
WHERE o.LocationList = N'NEWBUILD'
GROUP BY
p.Component
) AS x;
SET #sql = N'
SELECT PlaceRef, Address1, StreetName, PostCode, SubStatus, BuildingType, BuildDate, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT
vwLocationCurrent.PlaceRef
,vwLocationCurrent.Address1
,vwLocationCurrent.StreetName
,vwLocationCurrent.PostCode
,vwLocationCurrent.SubStatus
,vwLocationCurrent.BuildingType
,vwLocationCurrent.BuildDate'
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ N' FROM vwLocationCurrent
INNER JOIN VwLocationListEntriesCurrent
ON vwLocationCurrent.PlaceRef = VwLocationListEntriesCurrent.PlaceRef
LEFT OUTER JOIN VwLocationComponentCurrent
ON vwLocationCurrent.PlaceRef = VwLocationComponentCurrent.PlaceRef
WHERE VwLocationListEntriesCurrent.LocationList = ''NEWBUILD''
GROUP BY
vwLocationCurrent.PlaceRef
,vwLocationCurrent.Address1
,vwLocationCurrent.StreetName
,vwLocationCurrent.PostCode
,vwLocationCurrent.SubStatus
,vwLocationCurrent.BuildingType
) AS p;'
;
PRINT #sql;
EXEC sp_executesql #sql;
I'm trying to Pivot a Table on X and Y position. The table is in a format similar to below.
Each row has a value which is relative to its Row and Column Position.'AThing' and 'FileName' are to be ignored in the data set.
So if this was pivoted we would get:
Iv'e been trying for a while but can't seem to figure it out, any ideas?
EDIT: Number of Fields are dynamic per 'FileName'. I have managed to extract the column names but not the data using:
-- Construct List of Columns to Pivot
SELECT #PivotCols =
STUFF(
(SELECT ',' + QUOTENAME(FieldName)
FROM #Data
GROUP BY ColPos, FieldName
ORDER BY ColPos ASC
FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #PivotQuery =
SELECT ' + #PivotCols + N'
FROM
(
SELECT ColPos, FieldName
FROM #Data
GROUP BY ColPos, FieldName
) x
PIVOT
(
MIN(ColPos)
FOR FieldName IN (' + #PivotCols + N')
) p'
EXEC sp_executesql #PivotQuery
Please try this code:
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(FieldName)
FROM (SELECT distinct p.FieldName FROM Tablename AS p
) AS x;
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.Value, p.FieldName, p.RowPos
FROM Tablename AS p
) AS j
PIVOT
(
MAX(Value) FOR FieldName IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
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.
I am using SQL Server 2012. I will like to get final result from #sql into a temp table.Here is my code so far. Thanks for your help.
IF OBJECT_ID ('tempdb.dbo.#MY_DT_CTE') IS NOT NULL DROP TABLE #MY_DT_CTE
CREATE TABLE #MY_DT_CTE
([ROWID] INT NOT NULL IDENTITY (1,1)
,[YYYYMM] INT
)
; WITH MY_DT_CTE AS
(
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-1),112)) AS [YYYYMM]
UNION
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-2),112)) AS [YYYYMM]
UNION
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-3),112)) AS [YYYYMM]
UNION
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-4),112)) AS [YYYYMM]
UNION
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-5),112)) AS [YYYYMM]
UNION
SELECT CONVERT(INT,CONVERT(VARCHAR(6),EOMONTH(GETDATE(),-6),112)) AS [YYYYMM]
)
INSERT INTO #MY_DT_CTE
SELECT [YYYYMM] FROM MY_DT_CTE
ORDER BY [YYYYMM] DESC;
-- SELECT * FROM #MY_DT_CTE
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(YYYYMM)
FROM (SELECT p.YYYYMM FROM #MY_DT_CTE AS p
GROUP BY p.YYYYMM) AS x;
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.YYYYMM FROM #MY_DT_CTE AS p
) AS j
PIVOT
(
COUNT(YYYYMM) FOR YYYYMM IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1,
'')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
Need to bring this result #sql into a temp table.
201605 201606 201607 201608 201609 201610
An easy way would be to use a global temporary table. This can be selected into in the dynamic SQL scope to automatically have the desired schema and still be available after that exits.
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
INTO ##GlobalTemp
FROM
(
SELECT p.YYYYMM FROM #MY_DT_CTE AS p
) AS j
PIVOT
(
COUNT(YYYYMM) FOR YYYYMM IN (' + STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
EXEC sp_executesql #sql;
SELECT *
FROM ##GlobalTemp
However this can cause issues with naming clashes if the code is ever executed concurrently.
It is possible to use a local temp table but the code is more involved as it involves creating a temp table at the upper scope and then using dynamic SQL to alter it to the dynamically determined schema before inserting into it.
CREATE TABLE #T
(
Dummy INT
);
SET #sql = 'ALTER TABLE #T ADD Dummy2 INT' + REPLACE(REPLACE(#columns, 'p.', ''), ']', '] int') + ';
ALTER TABLE #T DROP COLUMN Dummy, Dummy2;'
EXEC (#sql);
SET #sql = N'
INSERT INTO #T
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.YYYYMM FROM #MY_DT_CTE AS p
) AS j
PIVOT
(
COUNT(YYYYMM) FOR YYYYMM IN (' + STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
EXEC sp_executesql #sql;
SELECT *
FROM #T