How to convert row data to column in sql server - sql

I have a table Test with 2 column Job_name and Status contains below data,
Job_Name status
------------------------
a failed
b completed
c waiting
d failed
I want output like below,
col1 col2 col3 col4
--------------------------------------
a b c d
failed completed waiting failed
I tried using pivot , but not able to achieve the exact output .
Please let me know , how can I proceed with this.
Thanks in advance.

Try this:
declare #x table (Job_Name char(1), [status] varchar(15))
insert into #x values
('a','failed'),
('b','completed'),
('c','waiting'),
('d','failed')
select * from
(
select 'col' + CAST(ROW_NUMBER() over (order by job_name) as varchar(2)) [colName],
[status]
from #x
) as [toPivot]
pivot
(
max([status])
for
colName in([col1],[col2],[col3],[col4])
) as [p1]
union all
select * from
(
select 'col' + CAST(ROW_NUMBER() over (order by job_name) as varchar(2)) [colName],
Job_Name
from #x
) as [toPivot]
pivot
(
max([job_name])
for
colName in([col1],[col2],[col3],[col4])
) as [p2]

Using a Dynamic Pivot
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..##Tmp') IS NOT NULL DROP TABLE ##Tmp
DECLARE #sql NVARCHAR(MAX)
DECLARE #cols nvarchar(max) = ''
DECLARE #hdrs nvarchar(max) = ''
DECLARE #Cols1 nvarchar(max) = ''
; WITH T (JOb_Name , Status) as
(
SELECT 'a' ,'failed'
UNION ALL
SELECT 'b' ,'completed'
UNION ALL
SELECT 'c' ,'waiting'
UNION ALL
SELECT 'd' , 'failed'
)
SELECT *
INTO ##Tmp
FROM t
SELECT #hdrs += ','+QUOTENAME(JOb_Name) + ' AS Col_'+ CAST(ROW_NUMBER () OVER(ORDER BY job_Name) AS nvarchar(5))
FROM ##Tmp
ORDER BY JOb_Name
SET #hdrs = STUFF(#hdrs,1,1,'')
SELECT #cols += ','+QUOTENAME(JOb_Name)
FROM ##Tmp
ORDER BY JOb_Name
SET #cols = STUFF(#Cols ,1,1,'')
SELECT #Cols1 += ','+QUOTENAME(Cols)
FROM
(
SELECT Job_Name, 'Col_' + CAST(ROW_NUMBER () OVER(ORDER BY job_Name) AS nvarchar(5)) Cols
FROM ##Tmp
) X
SET #Cols1 = STUFF (#cols1,1,1,'')
SET #sql =
'
SELECT *
FROM
(
SELECT Job_Name, ''Col_'' + CAST(ROW_NUMBER () OVER(ORDER BY job_Name) AS nvarchar(5)) Cols
FROM ##Tmp
) x
PIVOT (
MAX(Job_Name) FOR Cols IN ('+#cols1+')
) P
UNION ALL
SELECT '+#hdrs+'
FROM ##Tmp
PIVOT (
MAX(Status) FOR Job_Name IN ('+#cols+')
) P
'
exec sp_executesql #sql
DROP TABLE ##Tmp

Related

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)

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 + ' ...

Normal pivot to convert into dynamic or any other

I have table with this kind of data
ID name St_dt points
1 Mohan 2017-07-10 50
1 Mohan 2017-07-07 30
I want result Set like this
Output :
ID name 2017-07-10 2017-07-07 Difference %
1 Mohan 50 30 20 66.7
I have implemented Pivot function and achieved above result
sample Script :
Select
ID,
name,
[2017-07-10],
[2017-07-07],
[Difference] = [2017-07-10] - [2017-07-07],
case when [2017-07-10] > [2017-07-07]
then cast(round (([2017-07-10] - [2017-07-07]) *1. / [2017-07-07] * 100, 2) as decimal(3,1))
else 0
end as [%]
from (
select ID,name,St_dt,points from Table
)T
PIVOT (MAX(points)FOR St_dt IN ([2017-07-10],[2017-07-07]) )PVT
Up to now this is fine but when I'm trying achieve the same in Dynamic Pivot I'm facing the issue at percentage calculation. How i can achieve in Dynamic.
Hope my question is clear
Please check my dynamic query up to Difference calculation unable to achieve percentage calculation in dynamic
Dynamic Script :
DECLARE #cols AS NVARCHAR(MAX)='';
DECLARE #query AS NVARCHAR(MAX)='';
DECLARE #select_cols AS NVARCHAR(MAX)='';
DECLARE #diff_cols varchar(MAX) = '';
SELECT #cols = #cols + QUOTENAME(St_dt) + ',' FROM (select distinct CONVERT(DATE,St_dt)St_dt from #T
) as tmp ORDER BY St_dt desc
SELECT #cols = substring(#cols, 0, len(#cols))
select #cols
Set #diff_Cols = stuff((SELECT '-Max('+Quotename(CONVERT(DATE, St_dt))+') '
FROM #T
group by St_dt
ORDER BY St_dt DESC
FOR xml path('')) ,1,1,'')
select #diff_cols
Select #query = '
Select ID,name,
'+#cols+',
Difference = '+#diff_cols+'
from (
SELECT ID,name,St_dt,points
FROM #T
)T
PIVOT (MAX(Points)FOR St_dt IN ('+#cols+') )PVT
GROUP BY ID,name,'+#cols+'
'
EXEC (#query)
Try this below ,It may helps you
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable
Declare #Table TABLE (ID INT,name VARCHAR(50),St_dt DATE,points INT)
INSERT INTO #Table
SELECT 1,'Harini','2017-07-10',50 Union all
SELECT 1,'Harini','2017-07-07',30
SELECT * INTO #TempTable FROM #Table
DECLARE #Sql NVARCHAR(max)
,#SelectSQL NVARCHAR(max)
,#COlumns NVARCHAR(max)
,#Previousday NVARCHAR(max)
,#Difference NVARCHAR(max)
,#CurrentDay NVARCHAR(max)
SELECT #COlumns=STUFF((SELECT ', '+ QUOTENAME(CAST(St_dt AS VARCHAR(10)))FROM #TempTable GROUP BY St_dt ORDER BY St_dt DESC FOR XML PATH('')),1,1,'')
SELECT #SelectSQL = STUFF((
SELECT ', ' + 'ISNULL( MAX( ' + QUOTENAME(CAST(St_dt AS VARCHAR(10))) +' )'+ ',' + '''0''' + ') AS ' + QUOTENAME(CAST(St_dt AS VARCHAR(10)))
FROM #TempTable GROUP BY St_dt ORDER BY ST_DT DESC
FOR XML PATH('')
), 1, 1, '')
SELECT #CurrentDay=SUBSTRING(#COlumns,CHARINDEX(',',#COlumns)+1,LEN(#COlumns)),#Previousday=SUBSTRING(#COlumns,0,CHARINDEX(',',#COlumns))
SET #Difference=#Previousday+' - '+ #CurrentDay
SET #Sql=N'
SELECT ID,name,'+#SelectSQL+', [Difference]='+#Difference+',
CASE WHEN '+#Previousday+' > '+#CurrentDay+' THEN
CAST(ROUND (('+#Difference+') *1./'+#CurrentDay+'* 100, 2) AS DECIMAL(3,1)) ELSE 0 END AS [%]
FROM (
SELECT ID,name,St_dt,points FROM #TempTable
)Src
PIVOT
(
MAX(points) FOR St_dt IN ('+#COlumns+')
)AS PVT
Group by PVT.ID,PVT.name,
PVT.'+#CurrentDay+',PVT.'+#Previousday+''
PRINT #Sql
EXECute(#Sql)
Result
ID name 2017-07-10 2017-07-07 Difference %
------------------------------------------------------
1 Harini 50 30 20 66.7

Pivot in SQL Server with where clause

I am in need for using Pivot in SQL for getting the rows converted in columns, but not able to do so with my pivot query.
create table TestTable
(
id int,
colVal int
)
insert into TestTable values(1,1)
insert into TestTable values(1,2)
insert into TestTable values(1,4)
insert into TestTable values(2,1)
insert into TestTable values(2,2)
insert into TestTable values(2,6)
I am trying to get the values of colVal in the columns based on the below query where clause.
select * from
(
Select ID,colVal
from TestTable
where ID=1
) as PV
pivot
(max(id) for colVal in([1], [2], [3])) piv
For every ID there can only be 3 colValues hence I have specified [1],[2],[3] in the pivot.
I am looking for output like
ID c1 c2 c3
1 1 2 4
Can anyone help me out here.
Just use Row_Number() to create the column sequence
select id,[1] as c1,[2] as c2,[3] as c3 from
(
Select ID
,col = row_number() over (Partition By ID Order by colVal)
,colVal
from TestTable
where ID=1
) as PV
pivot
(max(colVal) for col in([1], [2], [3])) piv
Returns
ID c1 c2 c3
1 1 2 4
EDIT - Dynamic Version
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(concat('C',row_number() over (Partition By ID Order by colVal)))
From TestTable
Order By 1
For XML Path('')
),1,1,'')
Select #SQL = '
Select [id],' + #SQL + '
From (
Select ID
,col = concat(''C'',row_number() over (Partition By ID Order by colVal))
,colVal
from TestTable
where ID=1
) A
Pivot (max(colVal) For [col] in (' + #SQL + ') ) p'
Exec(#SQL);
EDIT for 2008
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName('C'+cast(row_number() over (Partition By ID Order by colVal) as varchar(10)))
From TestTable
Order By 1
For XML Path('')
),1,1,'')
Select #SQL = '
Select [id],' + #SQL + '
From (
Select ID
,col = ''C''+cast(row_number() over (Partition By ID Order by colVal) as varchar(10))
,colVal
from TestTable
where ID=1
) A
Pivot (max(colVal) For [col] in (' + #SQL + ') ) p'
Exec(#SQL);

How to provide custom name to column in pivoting

I have a table like this:
id unit
1 mm
2 cm
3 kg
When I perform pivot operation on this, I am getting result as follows:
1 2 3
mm cm kg
Is it possible to get custom column names here, something like this:
d1 d2 d3
mm cm kg
I am using Pivot for this as:
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE table #t
(id varchar(max),unit varchar(max))
insert into #t (id,unit)values
(1,'kg'),
(2,'cm'),
(3,'mm'),
(4,'m')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ',', '') + N'[' + cast(tbl.id as varchar(max)) + ']'
FROM (
SELECT DISTINCT id
FROM #t
) AS tbl
SELECT #statement = 'select *
INTO ##temp
from (
SELECT id,[unit]
FROM #t
) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
SELECT * FROM ##temp
DROP TABLE #t
DROP TABLE ##temp
Is it possible?
Thanks
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t (
id VARCHAR(10),
unit VARCHAR(100)
)
INSERT INTO #t (id, unit)
VALUES
('1', 'kg'),
('2', 'cm'),
('3', 'mm'),
('4', 'mm')
DECLARE #SQL NVARCHAR(MAX), #columns NVARCHAR(MAX)
SELECT #columns = STUFF((
SELECT ',[D' + id + ']'
FROM #t
FOR XML PATH('')), 1, 1, '')
SELECT #SQL = '
SELECT *
FROM (
SELECT [unit], col = N''D'' + id
FROM #t
) s
PIVOT (MAX(unit) FOR col IN (' + #columns + ')) p'
EXEC sys.sp_executesql #SQL
Just add a prefix to your ID. Example
SELECT #statement = 'select * INTO ##temp from
( SELECT [id] = ''d''+id,[unit] FROM #t ) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt '
Also it's terrible practice to use global temp tables! Especially one named ##temp
You can use a CASE expression with a dynamic sql query.
CREATE TABLE #t
(
id INT,
unit VARCHAR(2)
);
INSERT INTO #t VALUES
(1,'mm'),
(2,'cm'),
(3,'kg');
DECLARE #query AS VARCHAR(MAX);
SELECT #query = 'SELECT ' +
STUFF
(
(
SELECT DISTINCT ',MAX(CASE WHEN id = '+ CAST(id AS VARCHAR(10))
+ ' THEN unit END) AS d' + CAST(id AS VARCHAR(10))
FROM #t
FOR XML PATH('')
),
1,1,'');
SELECT #query += ' FROM #t;';
EXECUTE(#query);
Result
+----+----+----+
| d1 | d2 | d3 |
+----+----+----+
| mm | cm | kg |
+----+----+----+
SELECT #statement = 'select * INTO ##temp from ( SELECT ''d''+id AS [id],[unit] FROM #t ) as s PIVOT (max(unit) FOR id in(' + #columns + ')) as pvt '