Pivot table data - sql

I have following data
NAME | RIGHTS |
Steven | add |
Steven | update |
Steven | delete |
Mark | update |
Mark | delete |
Joseph | don’t have Rights |
Spike | add |
Spike | update |
Spike | delete |
And this data, I want to manipulate as
NAMEs | don’t have Rights | add| update | delete |
Steven | 0 |1|1|1|
Mark |0|0|1|1|
Joseph |1|0|0|0|
Spike |0|1|1|1|
Note that I have no idea of types of rights, it can be above 100

**Using pivot to get that result :**
CREATE TABLE #details(Id INT,NAME VARCHAR(100), RIGHTS VARCHAR(100))
INSERT INTO #details( Id ,NAME , RIGHTS )
SELECT 1,'Steven','add' UNION ALL
SELECT 1,'Steven','update' UNION ALL
SELECT 1,'Steven','delete' UNION ALL
SELECT 1,'Mark','update' UNION ALL
SELECT 1,'Mark','delete' UNION ALL
SELECT 1,'Joseph','don’t have Rights' UNION ALL
SELECT 1,'Spike','add' UNION ALL
SELECT 1,'Spike','update' UNION ALL
SELECT 1,'Spike','delete'
SELECT *
FROM
(
SELECT NAME , RIGHTS ,Id
FROM #details
)A
PIVOT
(
MAX(Id) FOR RIGHTS IN ([don’t have Rights],[add],[update],[delete])
)pvt
**For Dynamic pivot use below query :**
DECLARE #DynamicCol VARCHAR(MAX) = '',#DynamicPvt VARCHAR(MAX) = ''
SELECT #DynamicCol =
(
SELECT STUFF ((SELECT DISTINCT ',' + '[' + RTRIM(RIGHTS) + ']' FROM
#details FOR XML PATH('')),1,1,'')
)
SET #DynamicPvt = 'SELECT *
FROM
(
SELECT NAME , RIGHTS ,Id
FROM #details
)A
PIVOT
(
MAX(Id) FOR RIGHTS IN ('+#DynamicCol+')
)pvt'
EXEC (#DynamicPvt)

I got the answer
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',[' + Rights +']'
from MyTableName
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Name,' + #cols + ' from
(
SELECT Name, Rights,1 as xCount FROM MyTableName
) x
pivot
(
count(xCount)
for Rights in (' + #cols + ')
) p '
execute(#query);

Check this.
select NAME,
case when [don’t have Rights] is not null then 1 else 0 end as [don’t have Rights] ,
case when [add] is not null then 1 else 0 end as [add] ,
case when [update] is not null then 1 else 0 end as [update] ,
case when [delete] is not null then 1 else 0 end as [delete]
from
(
select *
from #YourTAble
pivot
(
max(RIGHTS) for RIGHTS in ([don’t have Rights],[delete],[update],[add])
)a
)b
Output :

Declare #Str varchar(max)
, #FinalStr varchar(max)
Set #Str=''
Select #Str = #Str + ',[' + Rights+']'
FROM (Select Distinct Rights FROM F2) A
Set #Str= Substring(#str,2,LEN(#Str))
SET #FinalStr =
'Select Name, ' + #Str +
'FROM F2
PIVOT ( Count(Rights)For Rights in ( ' + #Str + ')) As A'
Exec (#FinalStr)
This is will give the desire result and it's dynamic too. You can have number of rights.

Related

Replace null values with 0 in PIVOT

I tried to convert the (null) values with 0 (zeros) output in PIVOT function but have no success.
Below is the table and the syntax I've tried:
SELECT DISTINCT isnull([DayLoad],0) FROM #Temp1
Data in the table #Temp1:
zone dayB templt cid DayLoad
other 10 other 1 2020-05-28
other 10 other 1 2020-05-29
other 10 other 1 2020-05-30
other 10 other 1 2020-05-31
other 4 other 1 2020-06-02
other 10 other 1 2020-06-02
other 10 other 1 2020-06-01
My request:
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CONVERT(NVARCHAR, [DayLoad], 106) + ']',
'[' + CONVERT(NVARCHAR, [DayLoad], 106) + ']')
FROM (SELECT DISTINCT [DayLoad] FROM #Temp1) PV
ORDER BY [DayLoad]
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT *
into #temptable
FROM
(
SELECT
''''+[zone]+'' '' + ''''+convert(varchar(50),[dayB])+''''+''+'' +'' ''+(case when [templt]=''Прочее'' then '''' else [templt] end)+'''' as [zone/dayB]
,[DayLoad]
,[cid]
,[dayB]
,[zone]
FROM #Temp1
) x
PIVOT
(
sum([cid])
FOR [DayLoad] IN ('+ #cols + ')
) p
select *
from #temptable
order by [zone],[dayB]
drop table #temptable
'
EXEC(#query)
DROP TABLE #Temp1
Please refer below example, when you have nulls and empty string, right option is to go with case statement,
SELECT DISTINCT case when ([DayLoad] is null or [DayLoad] = '') then 0 else [DayLoad] end FROM #Temp1

Pivot Table with Dynamic

My quest might be answered in somewhere here but I couldn't find. So, sorry if I asked in vain.
I have a Table that's populate automatically with precisely date/time in SQL Server and looks like this:
Cod_Analise| Dat_analise | Nom_usuario| Resultado
-----------+-----------------+------------+-----------
1 | 02/20/2019 14:30| John | 4.5
2 | 02/20/2019 14:31| Carl | 60
3 | 02/21/2019 17:25| Carl | 17
2 | 02/19/2019 06:00| Marcus | 58
1 | 02/20/2019 15:40| Jorge | 5.2
2 | 02/21/2019 22:00| John | 58
and I need something like this:
Dat_Analise | 1 | 2 | 3 | Nom_usuario
------------+---+---+---+------------
02/19/2019 | 0 |58 | 0 | Marcus
02/20/2019 |4.9|60 | 0 | (First or Last one)
I need to do a pivot table based in this table where the Columns are Dat_Analise(date), Nom_operador(who did) and "Cod_Analise"(what did). And the rows are "Resultados"(results).
My problem is, i need to group by time period taking avg results for dynamic number of Cod_analises. But I even did the pivot with dynamic columns but I cannot fit the Group By part inside the pivot table.
I try to use a model that i found here and my procedure is like this:
SELECT
A.[RESULTADO],
A.[DAT_ANALISE],
A.[NOM_USUARIO],
B.[NOM_ANALISE]
into #temporaria
FROM
[BSDB_Processo].[dbo].[RESULTADOS_ANALISES] A,
[BSDB_Processo].[dbo].[ANALISES] B
WHERE
A.COD_PROCESSO = #PROCESSO
AND
A.COD_ANALISE = B.COD_ANALISE
AND
NUM_LOTE =#LOTE
Then:
declare #columnsSrc nvarchar(max) = N''
,#columnsDst nvarchar(max) = N''
,#sql nvarchar(max)
,#KeyColumns nvarchar(max) = N'DAT_ANALISE'
,#compatibility int = (
select top 1 compatibility_level from sys.databases
where name = db_name()
order by Name
);
declare #GroupBy nvarchar(max) =
--case when #compatibility <= 90
-- then case when len(#KeyColumns)=0 then '' else 'group by ' + #KeyColumns +
-- ' with rollup' end
-- else case when len(#KeyColumns)=0 then '' else 'group by rollup ('
-- + #KeyColumns + ')' end
-- end
case when len(#KeyColumns)=0 then '' else 'group by ' + #KeyColumns end;
select
#columnsSrc += nchar(10) + N',' + quotename([NOM_ANALISE])
,#columnsDst += nchar(10) + N',sum(isnull(' + quotename([NOM_ANALISE]) + N',0)) as '
+ quotename([NOM_ANALISE])
from (
select [NOM_ANALISE]
from #temporaria
group by [NOM_ANALISE]
) as x
order by x.[NOM_ANALISE]
And:
set #sql = N'
select ' +
case when len(#KeyColumns)=0 then '' else #KeyColumns + ',' end +
STUFF(#columnsDst, 1, 2, '') + '
INTO ##tabelaAnalises
from (
select' + nchar(10) +
case when len(#KeyColumns)=0 then '' else #KeyColumns + ',' end +
' [NOM_ANALISE],[RESULTADO]
from #temporaria
) as j
pivot (
sum([RESULTADO]) for [NOM_ANALISE] in ('
+ stuff(replace(#columnsSrc, ',p.[', ',['), 2, 1, '')
+ ')
) as p' + nchar(10) +
#GroupBy +
';'
>;
--print #sql;
exec sp_executesql #sql;
select * from ##tabelaAnalises
commit
End
Hope you can help me guys and ,again, sorry if i did something wrong with this post. First time using this
Try to see the below query. Please, see UPDATE section of a pivot with column Nom_usuario.
Sample data:
IF OBJECT_ID('tempdb..#SomeTable') IS NOT NULL DROP TABLE #SomeTable
GO
CREATE TABLE #SomeTable
(
Cod_Analise int,
Dat_analise datetime,
Nom_usuario varchar(50),
Resultado numeric(18,1)
)
INSERT INTO #SomeTable
(
Cod_Analise,
Dat_analise,
Nom_usuario,
Resultado
)
VALUES
( 2, '20190219 06:00', 'Marcus', 58)
, ( 1, '20190220 14:30', 'John', 4.5)
, ( 2, '20190220 14:31', 'Carl', 60)
, ( 1, '20190220 15:40', 'Jorge', 5.2)
, ( 3, '20190221 17:25', 'Carl', 17)
, ( 2, '20190221 22:00', 'John', 58)
A query:
SELECT
pvt.Dat_analise
, pvt.[1]
, pvt.[2]
, pvt.[3]
FROM
(SELECT
CONVERT(date, (t.Dat_analise)) Dat_analise
, t.Cod_Analise
, t.Resultado
FROM #SomeTable t) AS t
PIVOT
(
AVG(T.Resultado)
FOR t.Cod_Analise IN ([1], [2], [3])
) pvt
And dynamic version:
declare #cols nvarchar(max);
declare #sql nvarchar(max);
select #cols = stuff((
select distinct
' , ' + CONCAT('[', CONVERT(varchar(10), t.Cod_Analise), ']')
from #SomeTable t
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,2,'')
select #sql = '
select p.Dat_Analise,' + #cols + '
from (
SELECT
CONVERT(date, (t.Dat_analise)) Dat_analise
, t.Cod_Analise
, t.Resultado
FROM #SomeTable t
) as t
pivot (AVG(T.Resultado)
FOR t.Cod_Analise in (' + #cols + ') ) p'
exec(#sql);
OUTPUT:
Dat_analise 1 2 3
2019-02-19 NULL 58.000000 NULL
2019-02-20 4.850000 60.000000 NULL
2019-02-21 NULL 58.000000 17.000000
UPDATE:
Use the following code snippet to show a Nom_usuario:
declare #cols nvarchar(max);
declare #sql nvarchar(max);
select #cols = stuff((
select distinct
' , ' + CONCAT('[', CONVERT(varchar(10), t.Cod_Analise), ']')
from SomeTable t
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,2,'')
select #sql = '
select *
from
(
SELECT
CONVERT(date, (t.Dat_analise)) Dat_analise
, t.Cod_Analise
, t.Resultado
, MAX(t.Nom_usuario) OVER (PARTITION BY CONVERT(DATE, (t.Dat_analise))) Nom_usuario
FROM SomeTable t
) as t
pivot (AVG(T.Resultado)
FOR t.Cod_Analise in (' + #cols + ') ) p'
exec(#sql);
OUTPUT:
Dat_analise Nom_usuario 1 2 3
2019-02-21 John NULL 58.000000 17.000000
2019-02-20 Jorge 4.850000 60.000000 NULL
2019-02-19 Marcus NULL 58.000000 NULL

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

How to pivot rows into colums dynamically SQL Server

I have a request which returns something like this:
--------------------------
Tool | Week | Value
--------------------------
Test | 20 | 3
Sense | 20 | 2
Test | 19 | 2
And I want my input to look like this:
-------------------------
Tool | W20 | W19
-------------------------
Test | 3 | 2
Sense | 2 | null
Basically, for every week I need to have a new column. The number of week and of tools is dynamic.
I have tried many things but nothing worked. Anybody have a solution ?
Try this
CREATE table #tst (
Tool varchar(50), [Week] int, Value int
)
insert #tst
values
('Test', 20, 3),
('Sense', 20,2),
('Test', 19, 2)
Here is the Dynamic Query:
DECLARE #col nvarchar(max), #query NVARCHAR(MAX)
SELECT #col = STUFF((SELECT DISTINCT ',' + QUOTENAME('W' + CAST([Week] as VARCHAR))
from #tst
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = '
SELECT *
FROM (
SELECT Tool,
Value,
''W'' + CAST([Week] as VARCHAR) AS WeekNo
FROM #tst
) t
PIVOT
(
MAX(t.Value)
FOR WeekNo IN (' + #col + ')
) pv
ORDER by Tool'
EXEC (#query)
Result
Tool W20 W19
=================
Sense 2 NULL
Test 3 2
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
( Tool varchar(5), Week int, Value int)
;
INSERT INTO #temp
( Tool , Week , Value )
VALUES
('Test', 20, 3),
('Sense', 20, 2),
('Test', 19, 2)
;
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max),
#col NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' +'w'+ tbl.[Week] + ']'
FROM (
SELECT DISTINCT CAST([Week] AS VARCHAR)[Week]
FROM #temp
) AS tbl
SELECT #statement = 'SELECT *
FROM
(
SELECT
Tool , ''w''+ CAST(Week AS VARCHAR) week , Value
FROM
#Temp
) src
PIVOT(MAX(Value)for Week in (' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
This is how I would do it ... If I understood your question correctly
if object_id('tempdb..#InputTool') is not null drop table #InputTool
create table #InputTool (Tool nvarchar(10), [20] int, [19] int)
insert into #InputTool (Tool, [20], [19])
values
('Test', 3, 2),
('Sense', 2, null)
declare #cols nvarchar(max)
select #cols = STUFF((SELECT ',' + QUOTENAME(name)
from tempdb.sys.columns
where object_id = object_id('tempdb..#InputTool')
and Column_id > 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #sqlquery nvarchar(max) =
'select Tool, Weeks, Value from (
select * from #InputTool
) as it
UNPIVOT
(
Value FOR Weeks IN (' + #cols + ')
) AS Weeks
order by Weeks desc'
execute (#sqlquery);
Give it a shot and let me know if it worked

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 '