Moving Column names to rows - sql

I have such a table with date as column name
but I would like to have these dates in one column in more than one row something like this:
Date Index
20170806 9206
20170813 8041
20170820 8861
20170827 8356
How can I do it in SQL Server

If you would like to go for more dynamic solution rather than hard coding all columns, the below scripts should work:
IF OBJECT_ID('TestTable') IS NOT NULL
DROP TABLE TestTable;
CREATE TABLE TestTable
(
[20170806] INT NOT NULL,
[20170813] INT NOT NULL,
[20170820] INT NOT NULL,
[20170827] INT NOT NULL
)
INSERT INTO TestTable VALUES (9206, 8041, 8861, 8356)
DECLARE #cols NVARCHAR(MAX),
#sql NVARCHAR(MAX)
SELECT #cols = COALESCE(#cols + ',', '') + QUOTENAME(c.COLUMN_NAME)
FROM INFORMATION_SCHEMA.[COLUMNS] AS c
WHERE c.TABLE_NAME = 'TestTable'
SET #sql = '
SELECT [Date],
[Index]
FROM TestTable
UNPIVOT([Index] FOR [Date] IN ('+ #cols +')) AS up'
exec sp_executesql #sql;

You can use UNPIVOT for this.
SELECT * FROM MyTable
UNPIVOT([Date] For [Index] IN( [20170806], [20170813], [20170820], [20170827])) UNPVT
In addition, if you want to make it dynamically, you can use this query too.
DECLARE #ColNames NVARCHAR(MAX)
= STUFF(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
(SELECT T.* FROM (VALUES(1)) AS DUMY(ID) LEFT JOIN MyTable T ON 1=2 FOR XML AUTO, ELEMENTS XSINIL )
,'<T xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">','')
,'</T>','')
,'_x0032_','2')
,' xsi:nil="true"/>','] ')
,'<',',[') ,1,1,'')
DECLARE #SqlQ NVARCHAR(MAX)
= 'SELECT * FROM MyTable UNPIVOT([Date] For [Index] IN( ' + #ColNames + ')) UNPVT'
EXEC sp_executesql #SqlQ

You could use pivot such as:
However, i dont know your exact table names
select field_names
from table_name
pivot
( index
for index in ( Date, Index)
) pivot
but a useful article to follow is
"https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx"

Designed the table (variable) structure as below.
Hopefully, it matches your table structure.
DECLARE #data TABLE
(
[20170806] INT,
[20170813] INT,
[20170820] INT,
[20170827] INT
)
INSERT INTO #data VALUES (9206, 8041, 8861, 8356)
SELECT * FROM #data
You can use UNPIVOT statement for this. If you have dynamic columns, check this.
SELECT [Date],[Index]
FROM
#data
UNPIVOT
(
[Index] FOR [Date] IN ([20170806], [20170813], [20170820], [20170827])
) AS unpivotTable;
and the output is

Related

How to Un Pivot the Table With Date Headers in Sql

I have the following Temp table with Date Header How to UnPivot this Table
I need Like This type result
Here is the solution to your Problem:
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsUnpivot
= stuff((select ','+quotename(C.name)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID('table')
for xml path('')), 1, 1, '')
set #query
= 'select sno,EmpId, Name, Date, Value
from table
unpivot
(
Date
FOR EmpId IN ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
I used dynamic query since if you don't know how much columns are there in your table.
You can also use below static query :
SELECT sno, EmpId, Name, Date, Value
FROM
(SELECT *
FROM table) p
UNPIVOT
(Date FOR EmpId IN
(01-Mar-18,02-Mar-18,03-Mar-18,04-Mar-18,05-Mar-18)
)AS unpvt;
try the following script:
SELECT [s#no], [Emp#ID], [Name], [Date], [Shiftid]
FROM
(SELECT * FROM table_name) SRC
UNPIVOT
([Date] FOR [Emp#ID]
IN ([01-Mar-18], [02-Mar-18], [03-Mar-18], [04-Mar-18], [05-Mar-18])
) UNPVT;

Pivot multiple columns with a column value repeats for each new column

I need your help to build an sql query/sp for the following output.
My table is with the following data:
I would like to generate output like the following:
Kindly note, here, FieldName are not just four as in the table, it varies.
Find below the data:
CREATE TABLE #Results
(
FieldName nvarchar(50),
FieldValue nvarchar(50),
RecordStaus int
);
INSERT INTO #Results(FieldName,FieldValue,RecordStaus)
VALUES ('Coverage',NULL,1)
,('Premium',NULL,2)
,('F1',100,1)
,('F2',100,1)
,('Coverage',200,1)
,('Premium',10,1)
,('F1',50,1)
,('F2',NULL,3)
,('Coverage',300,1)
,('Premium',45,1)
,('F1',24,1)
,('F2',NULL,1)
,('Coverage',450,3)
,('Premium',12,3)
,('F1',50,1)
,('F2',NULL,1);
You can try this:
CREATE TABLE #Results
(
id int identity(1,1),
FieldName nvarchar(50),
FieldValue nvarchar(50),
RecordStaus int
);
INSERT INTO #Results(FieldName,FieldValue,RecordStaus)
VALUES ('Coverage',NULL,1)
,('Premium',NULL,2)
,('F1',100,1)
,('F2',100,1)
,('Coverage',200,1)
,('Premium',10,1)
,('F1',50,1)
,('F2',NULL,3)
,('Coverage',300,1)
,('Premium',45,1)
,('F1',24,1)
,('F2',NULL,1)
,('Coverage',450,3)
,('Premium',12,3)
,('F1',50,1)
,('F2',NULL,1);
DECLARE #DynamicTSQLStatement NVARCHAR(MAX)
,#Columns NVARCHAR(MAX);
SELECT #Columns = STUFF
(
(
SELECT *
FROM
(
SELECT DISTINCT ',[' + CAST([FieldName] AS NVARCHAR(50)) + ']'
FROM #Results
UNION
SELECT DISTINCT ',[' + CAST([FieldName] + '_RecordStaus' AS NVARCHAR(50)) + ']'
FROM #Results
) DS ([FieldName])
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
);
SET #DynamicTSQLStatement = N'
SELECT *
FROM
(
SELECT [FieldName]
+ CASE WHEN [Column] = ''RecordStaus'' THEN ''_RecordStaus'' ELSE '''' END AS [FieldName]
,[rowID]
,[Value]
FROM
(
SELECT [FieldName]
,[FieldValue]
,CAST([RecordStaus] AS NVARCHAR(50))
,ROW_NUMBER() OVER (PARTITION BY [FieldName] ORDER BY [id])
FROM #Results
) DS ([FieldName], [FieldValue], [RecordStaus], [rowID])
UNPIVOT
(
[Value] FOR [Column] IN ([FieldValue], [RecordStaus])
) UNPVT
) ReadyForPivot
PIVOT
(
MAX([Value]) FOR [FieldName] IN (' + #Columns +')
) PVT;
';
EXEC sp_executesql #DynamicTSQLStatement;
DROP TABLE #Results;
Few notes:
I have added id column in order to know the value for which row / in your real case you can use ordering by something else or SELECT 1 in the ROW_NUMBER function; you need such way in order to be sure the results are deterministic;
I am using dynamic SQL in order to make the query work for various values of FildName column - if you need specific order of the columns, you can do this using ORDER BY clause in the FOR XML clause. For example:
SELECT #Columns = STUFF
(
(
SELECT *
FROM
(
SELECT DISTINCT ',[' + CAST([FieldName] AS NVARCHAR(50)) + ']'
FROM #Results
UNION
SELECT DISTINCT ',[' + CAST([FieldName] + '_RecordStaus' AS NVARCHAR(50)) + ']'
FROM #Results
) DS ([FieldName])
ORDER BY [FieldName] DESC -- you can order the columns as you like
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
);
Then add the #columns variable value in the dynamic SQL:
SET #DynamicTSQLStatement = N'
SELECT' + #columns + ' ...

Create dynamic select get value for column name - in SQL Server

Please help me create a select SQL statement with the results column name get from the column values in origin table (tablename is Device_Part):
User can input many DeviceCode which have many dynamic PartTypeName, the PartTypeName value is the PartInfo.
This may help:
CREATE Table Device (
DeviceCode NVARCHAR(100) NOT NULL,
PartTypeName NVARCHAR(100) NOT NULL,
PartInfo NVARCHAR(100) NOT NULL
)
Insert Into Device
Values('VT.SX-01','CPU','Pentium G6650'),
('VT.SX-01','Motherboard','H81M - S2PV'),
('VT.SX-01','RAM','DDR# 4GB - bus 1866 - Nano'),
('VT.SX-01','PartType Name 01','PartInfo 01')
--QUERY
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX);
DECLARE #ColumnNamesInPivot AS NVARCHAR(MAX);
--Get distinct values of PIVOT Column
SELECT #ColumnNamesInPivot = ISNULL(#ColumnNamesInPivot + ',', '')
+ QUOTENAME([PartTypeName])
FROM ( SELECT DISTINCT
[PartTypeName]
FROM Device
) AS P
SELECT #DynamicPivotQuery = N'Select DeviceCode,'
+ #ColumnNamesInPivot + '
FROM ( SELECT *
FROM Device
) AS SourceTable PIVOT( MAX(PartInfo) FOR [PartTypeName] IN ('
+ #ColumnNamesInPivot + ') ) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery;
And the result will be:
Try this
;WITH _CTE(_DeviceCode,_PartTypeName,_PartInfo,_Id)
AS
(
SELECT DeviceCode,PartTypeName,PartInfo ,ROW_NUMBER() OVER (PARTITION BY PartTypeName ORDER BY Id) FROM Your_tablename
)
SELECT *
FROM
(
SELECT _DeviceCode,_PartTypeName,_PartInfo
FROM _CTE
)C
PIVOT
(
MAX(_PartInfo) FOR _PartTypeName IN ([CPU],[MotherBoard],[RAM],[PartTypeName])
) AS PivotTable;

using temp tables in SQL Azure

I am writing a query to pivoting table elements where column name is generated dynamically.
SET #query = N'SELECT STUDENT_ID, ROLL_NO, TITLE, STUDENT_NAME, EXAM_NAME, '+
#cols +
' INTO ##FINAL
FROM
(
SELECT *
FROM #AVERAGES
UNION
SELECT *
FROM #MARKS
UNION
SELECT *
FROM #GRACEMARKS
UNION
SELECT *
FROM #TOTAL
) p
PIVOT
(
MAX([MARKS])
FOR SUBJECT_ID IN
( '+
#cols +' )
) AS FINAL
ORDER BY STUDENT_ID ASC, DISPLAYORDER ASC, EXAM_NAME ASC;'
EXECUTE(#query)
select * from ##FINAL
This query works properly in my local database, but it doesn't work in SQL Azure since global temp tables are not allowed there.
Now if i change ##FINAL to #FINAL in my local database, but it gives me error as
Invalid object name '#FINAL' .
How can I resolve this issue?
Okay, after saying I didn't think it could be done, I might have a way. It's ugly though. Hopefully, you can play with the below sample and adapt it to your query (without having your schema and data, it's too tricky for me to attempt to write it):
declare #cols varchar(max)
set #cols = 'object_id,schema_id,parent_object_id'
--Create a temp table with the known columns
create table #Boris (
ID int IDENTITY(1,1) not null
)
--Alter the temp table to add the varying columns. Thankfully, they're all ints.
--for unknown types, varchar(max) may be more appropriate, and will hopefully convert
declare #tempcols varchar(max)
set #tempcols = #cols
while LEN(#tempcols) > 0
begin
declare #col varchar(max)
set #col = CASE WHEN CHARINDEX(',',#tempcols) > 0 THEN SUBSTRING(#tempcols,1,CHARINDEX(',',#tempcols)-1) ELSE #tempcols END
set #tempcols = CASE WHEN LEN(#col) = LEN(#tempcols) THEN '' ELSE SUBSTRING(#tempcols,LEN(#col)+2,10000000) END
declare #sql1 varchar(max)
set #sql1 = 'alter table #Boris add [' + #col + '] int null'
exec (#sql1)
end
declare #sql varchar(max)
set #sql = 'insert into #Boris (' + #cols + ') select ' + #cols + ' from sys.objects'
exec (#sql)
select * from #Boris
drop table #Boris
They key is to create the temp table in the outer scope, and then inner scopes (code running within EXEC statements) have access to the same temp table. The above worked on SQL Server 2008, but I don't have an Azure instance to play with, so not tested there.
If you create a temp table, it's visible from dynamic sql executed in your spid, if you create the table in dynamic sql, it's not visible outside of that.
There is a workaround. You can create a stub table and alter it in your dynamic sql. It requires a bit of string manipulation but I've used this technique to generate dynamic datasets for tsqlunit.
CREATE TABLE #t1
(
DummyCol int
)
EXEC(N'ALTER TABLE #t1 ADD foo INT')
EXEC ('insert into #t1(DummyCol, foo)
VALUES(1,2)')
EXEC ('ALTER TABLE #t1 DROP COLUMN DummyCol')
select *from #t1

Getting a Dynamically-Generated Pivot-Table into a Temp Table

I've seen this, so I know how to create a pivot table with a dynamically generated set of fields. My problem now is that I'd like to get the results into a temporary table.
I know that in order to get the result set into a temp table from an EXEC statement you need to predefine the temp table. In the case of a dynamically generated pivot table, there is no way to know the fields beforehand.
The only way I can think of to get this type of functionality is to create a permanent table using dynamic SQL. Is there a better way?
Ran in to this issue today, and posted on my blog. Short description of solution, is to create a temporary table with one column, and then ALTER it dynamically using sp_executesql. Then you can insert the results of the dynamic PIVOT into it. Working example below.
CREATE TABLE #Manufacturers
(
ManufacturerID INT PRIMARY KEY,
Name VARCHAR(128)
)
INSERT INTO #Manufacturers (ManufacturerID, Name)
VALUES (1,'Dell')
INSERT INTO #Manufacturers (ManufacturerID, Name)
VALUES (2,'Lenovo')
INSERT INTO #Manufacturers (ManufacturerID, Name)
VALUES (3,'HP')
CREATE TABLE #Years
(YearID INT, Description VARCHAR(128))
GO
INSERT INTO #Years (YearID, Description) VALUES (1, '2014')
INSERT INTO #Years (YearID, Description) VALUES (2, '2015')
GO
CREATE TABLE #Sales
(ManufacturerID INT, YearID INT,Revenue MONEY)
GO
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(1,2,59000000000)
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(2,2,46000000000)
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(3,2,111500000000)
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(1,1,55000000000)
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(2,1,42000000000)
INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(3,1,101500000000)
GO
DECLARE #SQL AS NVARCHAR(MAX)
DECLARE #PivotColumnName AS NVARCHAR(MAX)
DECLARE #TempTableColumnName AS NVARCHAR(MAX)
DECLARE #AlterTempTable AS NVARCHAR(MAX)
--get delimited column names for various SQL statements below
SELECT
-- column names for pivot
#PivotColumnName= ISNULL(#PivotColumnName + N',',N'') + QUOTENAME(CONVERT(NVARCHAR(10),YearID)),
-- column names for insert into temp table
#TempTableColumnName = ISNULL(#TempTableColumnName + N',',N'') + QUOTENAME('Y' + CONVERT(NVARCHAR(10),YearID)),
-- column names for alteration of temp table
#AlterTempTable = ISNULL(#AlterTempTable + N',',N'') + QUOTENAME('Y' + CONVERT(NVARCHAR(10),YearID)) + ' MONEY'
FROM (SELECT DISTINCT [YearID] FROM #Sales) AS Sales
CREATE TABLE #Pivot
(
ManufacturerID INT
)
-- Thats it! Because the following step will flesh it out.
SET #SQL = 'ALTER TABLE #Pivot ADD ' + #AlterTempTable
EXEC sp_executesql #SQL
--execute the dynamic PIVOT query into the temp table
SET #SQL = N'
INSERT INTO #Pivot (ManufacturerID, ' + #TempTableColumnName + ')
SELECT ManufacturerID, ' + #PivotColumnName + '
FROM #Sales S
PIVOT(SUM(Revenue)
FOR S.YearID IN (' + #PivotColumnName + ')) AS PivotTable'
EXEC sp_executesql #SQL
SELECT M.Name, P.*
FROM #Manufacturers M
INNER JOIN #Pivot P ON M.ManufacturerID = P.ManufacturerID
you could do this:
-- add 'loopback' linkedserver
if exists (select * from master..sysservers where srvname = 'loopback')
exec sp_dropserver 'loopback'
go
exec sp_addlinkedserver #server = N'loopback',
#srvproduct = N'',
#provider = N'SQLOLEDB',
#datasrc = ##servername
go
declare #myDynamicSQL varchar(max)
select #myDynamicSQL = 'exec sp_who'
exec('
select * into #t from openquery(loopback, ''' + #myDynamicSQL + ''');
select * from #t
')
EDIT: addded dynamic sql to accept params to openquery
Let me try this explanation of select into instead. I'm running SQL Server 2005 as well. Because you have PIVOT tables I'm going to assume the same or 2008.
select
o.*,
OtherField1,
OtherField2
INTO #temp
FROM
OriginalOtherData as ood
PIVOT (
MAX([Value])
FOR Field in (OtherField1, OtherField2)
) as piv
RIGHT OUTER join
Original o on o.OriginalSD = piv.OriginalSD
select * from #temp
Drop table #temp
The only difference between a normal select and a select into is that INTO #table part.
for query (select col1, col2, col3 from tablename
col1 becomes rowlabels
col2 becomes columnheaders
col3 is the dataset
also gets rid of the global table
if OBJECT_ID('tempdb..#3') is not null drop table #3
if OBJECT_ID('tempdb..##3') is not null drop table ##3
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME( col2 ) from tablename FOR XML PATH(''), col2).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT col1, ' + #cols + ' into ##3 from ( select col1, col2, col3 from tablename ) x pivot ( max(col3)for col2 in (' + #cols + ')) p '
execute(#query)
select * into #3 from ##3 if OBJECT_ID('tempdb..##3') -- is not null drop table ##3