Pivot in SQL Server with where clause - sql

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);

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)

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.

How to convert row data to column in sql server

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

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

Transpose / Dynamic PIVOT

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