Transpose / Dynamic PIVOT - sql

into the following:
Credit is limited with 6. Blank spots can be null. I want to create new columns named as Credit1,Credit2, .. ,Credit6. Can I use PIVOT for this scenario? Or any other simple way to transpose the table?

You could use dynamic SQL version:
CREATE TABLE #SampleData
(
Name varchar(50),
Credits int
)
INSERT INTO #SampleData
VALUES ('John', 10),('John', 20),
('Bath', 90), ('Bath', 60), ('Bath', 70),('Bath', 80),('Bath', 50),
('Richard', 75)
DECLARE #ColPivot nvarchar(max)
;WITH temp AS
(
SELECT * , 'Credit' + CAST(row_number() OVER(PARTITION BY sd.Name ORDER BY (SELECT 1)) AS varchar(5)) AS CreditGroup
FROM #SampleData sd
)
SELECT #ColPivot = STUFF(
(SELECT DISTINCT ',' + t.CreditGroup FROM temp t FOR XML PATH (''))
,1,1,'')
DECLARE #query nvarchar(max) =
N';WITH temp AS
(
SELECT * , ''Credit'' + CAST(row_number() OVER(PARTITION BY sd.Name ORDER BY (SELECT 1)) AS varchar(5)) AS CreditGroup
FROM #SampleData sd
)
Select [Name], ' + #ColPivot +
' FROM
(
SELECT [Name], Credits, CreditGroup FROM temp
) src
PIVOT
(
MAX(Credits) FOR CreditGroup IN ('+ #ColPivot+ ')
)pvt
'
PRINT #query
EXEC (#query)
DROP TABLE #SampleData
Demo link: Rextester

Related

Dynamic pivot in SQL server: insert spaces in concatenation and referencing a pivot

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

Splicing SQL display Chinese characters problem

I have following SQL script which I hope to cross apply to select Chinese column name
CREATE TABLE #temp([color] varchar(5), [size] varchar(5),[AQty] varchar(10),[BQty] varchar(10),[CQty] varchar(10),[DQty] varchar(10));
INSERT INTO #temp([color], [size], [AQty], [BQty],[CQty],[DQty])
VALUES ('A1', 'L','1','2','3','4')
, ('A1', 'M','1','2','3','4')
, ('A1', 'S','1','2','3','4')
, ('A1', 'XL','1','2','3','4')
, ('B1', 'L','1','2','3','4')
, ('B1', 'M','1','2','3','4')
, ('B1', 'S','1','2','3','4')
, ('B1', 'XL','1','2','3','4')
, ('B1', 'XXL','1','2','3','4')
, ('C1', 'L','1','2','3','4')
, ('C1', 'S','1','2','3','4')
declare #cols as varchar(max), #sql varchar(max)
select #cols = STRING_AGG(col, ', ') from (
select distinct QUOTENAME(size) as col from #temp
) as t
set #sql = '
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select ''总数一'', cast(AQty as varchar(10)) union all
select ''总数二'', cast(BQty as varchar(10)) union all
select ''总数三'', cast(CQty as varchar(10)) union all
select ''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
But now exec SQL is display garbled when I hope to display Chinese column name
color total L M S XL XXL
A1 ??? 4 4 4 4 NULL
B1 ??? 4 4 4 4 4
C1 ??? 4 NULL4 NULLNULL
I tried to change it like this, change variable nvarchar, set #sql with N and change cross apply select with N, but now not work.
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
I have solved my problem by adding N after + #cols +
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + N'
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)

How to create a table with pivot results using SELECT * INTO ( PIVOT Result query) [duplicate]

I have the following schema and sample data.
create table MyTable
(
Id int,
Year int,
Channel varchar(10),
Payments int
)
insert into MyTable values
(1,2012,'HV',100),
(1,2014,'HV',56),
(2,2012,'NL',17000)
(2,2012,'HV',495),
(3,2013,'HV',565)
Now I want to create and insert dynamic pivot data in a temporary table. I am able to create the pivot data as the demo here.
But I want to store this data into a temporary table. What I have tried is as below.
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.Id
,B.*
From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year)
)) B (Item,Value)
) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'') + ') ) p'
select #SQL
Exec(#SQL);
SELECT * FROM ##TempTable
It is giving me the following error.
Msg 102, Level 15, State 1, Line 18 Incorrect syntax near '+'.
When printing the dynamic query it is giving the following result.
if object_id('tempdb..##TempTable') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, [HV2012] Varchar(20) null,[HV2013] Varchar(20) null,[HV2014] Varchar(20) null,[NL2012] Varchar(20) null)
INSERT INTO ##TempTable
Select * From ( Select A.Id ,B.* From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year) )) B (Item,Value) ) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p
If you are using apply then why you need further same logic in PIVOT (i.e. Channel + CONVERT(Varchar(4), Year)) which is already available in apply.
So, i would use Value instead in PIVOT :
. . .
Pivot (sum([Payments]) For [Value] in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p,
So, your updated Dynamic SQL would be :
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.ID, A.Payments
,B.*
From [dbo].MyTable a
Cross Apply ( values ( Channel + CONVERT(Varchar(4), Year)
)) B ([Value])
) S
Pivot (sum([Payments]) For [Value] in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From #tm
Order By 1
For XML Path('')),1,1,'') + ') ) p'
print #sql
Exec(#SQL)
SELECT * FROM ##TempTable
I have made no of changes as there are many correction needs to be done prior to execution.

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;