Related
I have a table in long format which I convert to wide format dynamically.
The code was heavily influenced by: SQL Server dynamic PIVOT query?
create table #temp
(
ID int,
category varchar(15),
Answer varchar (5)
)
insert into #temp values ('1', 'breakfast','yes')
insert into #temp values ('1', 'lunch','no')
insert into #temp values ('1', 'dinner','yes')
insert into #temp values ('2', 'breakfast','no')
insert into #temp values ('2', 'lunch', 'yes')
insert into #temp values ('2', 'dinner', 'no')
select * from #temp
Which I can convert into wide format:
DECLARE #cols AS VARCHAR(MAX)='';
DECLARE #query AS VARCHAR(MAX)='';
SELECT #cols = #cols + QUOTENAME(category) + ',' FROM (select distinct category from #temp ) as tmp
select #cols = substring(#cols, 0, len(#cols))
exec (
'SELECT ID, '+#cols+', concat('+#cols+' )as NewCol from
(
select ID, category,answer from #temp
) pivotexample
pivot
(
max(Answer) for category in (' + #cols + ')
) as pivotexample2'
)
drop table #temp
The distinct values in the category column can change so I needed a dynamic solution (as above). This give the below pivoted output:
The issue I have is how can I insert a separator in the concatenation part that creates NewColumn in the pivot.
Also when I then run a select * from pivotexample2 query, it says Invalid object name 'pivotexample2'. I don't understand why this is, because this is the alias I have given it and want to reference it for things like joins further in the pipeline. How can I give it an alias so I can refence it again? Is it possible to put the pivot within a CTE so I can refence it again?
You can use concat_ws:
DECLARE #cols AS VARCHAR(MAX)='';
DECLARE #query AS VARCHAR(MAX)='';
SELECT #cols = #cols + QUOTENAME(category) + ',' FROM (select distinct category from #temp ) as tmp
select #cols = substring(#cols, 0, len(#cols))
exec (
'SELECT ID, '+#cols+', concat_ws('','', '+#cols+' )as NewCol from
(
select ID, category,answer from #temp
) pivotexample
pivot
(
max(Answer) for category in (' + #cols + ')
) as pivotexample2'
)
drop table #temp
It would return:
ID
breakfast
dinner
lunch
NewCol
1
yes
yes
no
yes,yes,no
2
no
no
yes
no,no,yes
DBFiddle: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=45dce502caf3b71662b963fb52dff94e
The question has been asked before, but in a slightly different scenario (one that doesn't seem to fit to my question) so..
I have data that looks like this
Name |Item |Note
George|Paperclip |Two boxes
George|Stapler |blue one
George|Stapler |red one
George|Desk lamp |No light bulb
Mark |Paperclip |One box 2"
Mark |Paperclip |One box 4"
Mark |Block Notes|a blue one
..? |..? |..?
And I would want to pivot by name, to obtain
Name |Paperclip|Stapler|Desk Lamp|Block Notes
George| 1| 2| 1| NULL
Mark | 2| NULL | NULL | 1
I've follower the examples like
Convert Rows to columns using 'Pivot' in SQL Server
but I'm far from a solution.. can someone please give me an hand?
Thanks!
edit: the actual code
drop table #temp2
SELECT DISTINCT *,
CASE WHEN Item IS NULL THEN NULL ELSE COUNT(Item) OVER(PARTITION BY Name) END CNT
INTO #TEMP2
FROM [ISPBIGFIX].[dbo].[C_INV_ErroriTavolette_v11]
DECLARE #cols NVARCHAR (MAX)
DECLARE #Columns2 NVARCHAR (MAX)
SET #cols = SUBSTRING((SELECT DISTINCT ',['+Item+']' FROM #TEMP2 GROUP BY Item FOR XML PATH('')),2,8000)
SET #Columns2 = SUBSTRING((SELECT DISTINCT ',ISNULL(['+Item+'],0) AS ['+Item+']' FROM #TEMP2 GROUP BY Item FOR XML PATH('')),2,8000)
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT Name,' + #Columns2 + ' FROM
(
SELECT Name,ErrorType,CNT FROM #TEMP2
) x
PIVOT
(
SUM(CNT)
FOR [Item] IN (' + #cols + ')
) p
WHERE Name IS NOT NULL;'
EXEC SP_EXECUTESQL #query
Try this, It follows the same example mentioned here:Convert Rows to columns using 'Pivot' in SQL Server
--Drop Sample temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
--create Sample temp Table
create Table #temp2
(
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
insert into #temp2
values( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
DECLARE #cols AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
--Generate Columns from Data
--Generate Columns from Data
select #cols = STUFF((SELECT ', isnull(' + QUOTENAME(Item) + ',0) as' + QUOTENAME(Item)
from #temp2
group by Item
order by Item
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols2 = STUFF((SELECT ', ' + QUOTENAME(Item)
from #temp2
group by Item
order by Item
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--Pivot Query
set #query = 'SELECT [name],' + #cols + ' from
(
select [Name], Item, count(*) as xcount
from #temp2
group by Name, Item
) x
pivot
(
sum(xCount)
for Item in (' + #cols2+ ')
) p '
execute(#query);
--Drop Sample Temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
Try This Dynamic Sql
IF OBJECT_ID('dbo.TT')IS NOT NULL
DROP TABLE TT
;WITH CTE(Name ,Item ,Note)
AS
(
SELECT 'George','Paperclip' ,'Two boxes' UNION ALL
SELECT 'George','Stapler' ,'blue one' UNION ALL
SELECT 'George','Stapler' ,'red one' UNION ALL
SELECT 'George','Desk lamp' ,'No light bulb' UNION ALL
SELECT 'Mark' ,'Paperclip' ,'One box 2' UNION ALL
SELECT 'Mark' ,'Paperclip' ,'One box 4' UNION ALL
SELECT 'Mark' ,'Block Notes','a blue one'
)
SELECT *,CASE WHEN Item IS NOT NULL THEN 1 ELSE 0 END AS Item2 INTO TT FROM CTE
SELECT * FROM TT
DECLARE #Sql nvarchar(max),
#Sqlcol nvarchar(max),
#ISNULLSqlcol nvarchar(max)
SELECT #Sqlcol=STUFF((SELECT DISTINCT ', '+QUOTENAME(Item)
FROM TT FOR XML PATH ('')),1,1,'')
SELECT #ISNULLSqlcol=STUFF((SELECT DISTINCT ', '+'ISNULL(SUM('+QUOTENAME(Item) +'),''0'') AS '+QUOTENAME(Item)
FROM TT FOR XML PATH ('')),1,1,'')
SET #Sql='SELECT Name,'+#ISNULLSqlcol+'FROM
(
SELECT * FROM TT
) AS SRc
PIVOT
(
SUM(Item2) FOR Item IN('+#Sqlcol+')
) AS Pvt GROUP BY Name'
Print #Sql
EXEC (#Sql)
Try this query (I think its much more clearly). I use the code of Kashif Qureshi to create a temporary table, but my code is different in PIVOT part
--Drop Sample temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
--create Sample temp Table
create Table #temp2
(
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
insert into #temp2
values( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
--- PIVOT
DECLARE #v_query VARCHAR(8000) -- main query
DECLARE #v_columns VARCHAR(8000) -- columns
SET #v_columns =''
-- Get string columns
SELECT #v_columns += '[' + CONVERT(VARCHAR, Item) +'],' FROM (SELECT DISTINCT Item FROM #temp2) AS temp
-- Delete the last comma
SET #v_columns = LEFT(#v_columns,LEN(#v_columns)-1)
-- Main query
SET #v_query = 'SELECT Name, ' + #v_columns +' FROM
(
SELECT Name, Item FROM #temp2
) T
PIVOT
(
Count(Item)
FOR Item IN ('+ #v_columns +')
) PVT'
EXEC (#v_query)
-- DROP
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
The answer by Kashif works. Here is a version that leverages STRING_AGG
--Drop Sample temp Table
DROP TABLE IF EXISTS #temp2
--Create Sample temp Table
CREATE Table #temp2 (
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
INSERT INTO #temp2
VALUES ( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
DECLARE #cols AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
--Generate Columns from Data
SET #cols = (SELECT STRING_AGG (' isnull(' + QUOTENAME(Item) + ',0) as' + QUOTENAME(Item), ',') as colR
FROM (SELECT ITEM FROM (SELECT ITEM FROM #temp2 GROUP BY ITEM) x GROUP BY ITEM) Y )
SET #cols2 = (SELECT STRING_AGG (QUOTENAME(Item), ',') as colR
FROM (SELECT ITEM FROM (SELECT ITEM FROM #temp2 GROUP BY ITEM) x GROUP BY ITEM) Y )
SET #query = 'SELECT [name],' + #cols + '
FROM (
SELECT [Name], Item, COUNT(*) as xcount
FROM #temp2
GROUP BY Name, Item
) x
PIVOT (
SUM(xCount)
FOR Item IN (' + #cols2+ ')
) p '
EXECUTE (#query);
--Drop Sample Temp Table
DROP TABLE IF EXISTS #temp2
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 + ' ...
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
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;