SQL - Pivoting on Column and Row Values - 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;

Related

How to make SQL Pivot display more than one row

I was able to display every row in column using pivot however when there are multiple values, it displays only one of the row values. My suspicion lies on the MAX function in the for loop, however, have not been able to find a successful replacement.
I've tried other SQL functions.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(Provincia)
FROM Codigos_Postales
GROUP BY Provincia
ORDER BY Provincia
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query = N'SELECT Poblacion,' + #cols + N' from
(
select * from Codigos_Postales
) x
pivot
(
MAX(Codigo_Postal)
for Provincia in (' + #cols + N')
) p ORDER BY Poblacion ASC'
EXEC sp_executesql #query;
Table I'm trying to pivot:
Result:
Expected Result:
If I understand corerctly, adding ROW_NUMBER to your source data will do the trick. The sample PIVOT script will be as below. Just ignore the RN column from your final output, that's it.
SET #query =
N'SELECT Poblacion,' + #cols + N' from
(
SELECT
ROW_NUMBER() OVER (ORDER BY Provincia) RN,
*
FROM Codigos_Postales
) x
PIVOT
(
MAX(Codigo_Postal)
FOR Provincia IN (' + #cols + N')
) p ORDER BY Poblacion ASC'

Save dynamic table as a view/table

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.

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.

Dynamic SQL SQL Server 2012 Get Result into a #temp table

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

is any other way to do in dynamic pivot

while answering one question i got struck with other question in mind.when it is normal pivot it is working fine but if i'm trying to do Dynamic query when the problem arises
after answering he asked for Dynamic Pivot
PIVOT the date column in SQL Server 2012
if OBJECT_ID('tempdb..#temp') is not null
begin
drop table #temp
end
CREATE table #temp (dated varchar(10),E1 int,E2 int,E3 int,E4 int)
insert into #temp
(dated,E1,E2,E3,E4)values
('05-27-15',1,1,2,3),
('05-28-15',2,3,NULL,5),
('05-29-15',3,4,null,2)
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' + tbl.dated + ']'
FROM (
SELECT DISTINCT dated
FROM #temp
) AS tbl
SELECT #statement = 'Select P.col,MAX('+#columns+') from (
select col,' + #columns + ' from (
select * from #temp
CROSS APPLY(values(''E1'',E1),(''E2'',E2),(''E3'',E3),(''E4'',E4))cs (col,val))PP
PIVOT(MAX(val) for dated IN (' + #columns + ')) as PVT)P
GROUP BY P.COL
'
PRINT #statement
EXEC sp_executesql #statement = #statement
my problem is how can i take MAX() conditions for the all dates dynamically like
max(05-27-15),max(05-28-15) etc dates are coming dynamically how to assign max condition
Moving the MAX aggregate to column list variable will fix the issue
DECLARE #statement NVARCHAR(max),
#columns NVARCHAR(max),
#select_columns NVARCHAR(max)
SELECT #select_columns = Isnull(#select_columns + ', ', '')+ N'MAX([' + tbl.dated + '])'
FROM (SELECT DISTINCT dated
FROM #temp) AS tbl
SELECT #columns = Isnull(#columns + ', ', '') + N'[' + tbl.dated+ ']'
FROM (SELECT DISTINCT dated
FROM #temp) AS tbl
SELECT #statement = 'Select P.col,' + #select_columns
+ ' from (
select col,' + #columns
+ ' from (
select * from #temp
CROSS APPLY(values(''E1'',E1),(''E2'',E2),(''E3'',E3),(''E4'',E4))cs (col,val))PP
PIVOT(MAX(val) for dated IN (' + #columns
+ ')) as PVT)P
GROUP BY P.COL
'
PRINT #statement
EXEC sp_executesql #statement = #statement