SQL Server : Pivot table - sql-server

create PROC [dbo].[Sample]
#fromDate datetime, #toDate datetime, #office varchar(30)
AS
declare #char varchar(200)
DECLARE #Temp TABLE (ID int, Name varchar(50), Countt int, Reason varchar(20))
INSERT INTo #Temp (ID, Name, Countt, Reason)
SELECT DD.ID, O.Name, Count(DD.Reason) Countt, convert(varchar,DD.Reason) Reason FROM samp1 AS DD
INNER JOIN samp3 AS O ON O.ID = DD.ID
select #char = coalesce(#char + ',', '') + reason from #Temp
select *
FROM
(
select distinct ID, Name, Reason, sum(Countt) as Countt from #Temp group by Name, Reason, ID
)P
PIVOT
(
SUM(Countt)
FOR Reason
IN (select #char)
) AS pvt
Error: Msg 156, Level 15, State 1, Procedure Sample, Line 45
Incorrect syntax near the keyword 'select'.
can anybody help me

SELECT #char = COALESCE(#char + ',[' + reason + ']', '[' + reason + ']')
FROM #Temp
DECLARE #pvtQuery VARCHAR(2500)
SET #pvtQuery =
'
SELECT ID, Name, ' + #char + '
FROM
(
SELECT DISTINCT ID, Name, Reason, SUM(Countt) AS Countt
FROM #Temp
GROUP BY Name, Reason, ID
) P
PIVOT
(
SUM(Countt)
FOR Reason
IN (' + #char + ')
) AS pvt
'
EXEC (#pvtQuery)

Related

MS SQL.Transform rows into columns

I have a simple table. As a result I need to get names of numeric columns and paste like rows and then paste its values like columns.Here is an example of table:
As a result I need to receive something like this:
I tried to get the result with PIVOT, but I have not the correct answer.
select * from (
select col1, 'val' + cast(row_number()over(partition by col1 order by col1) as nvarchar(20)) ColVal
from mytbl
) tmp
pivot (
min(col1) for ColVal in (val1,val2)
) pvt
In this case you need to unpivot first, then pivot back:
DROP TABLE IF EXISTS dbo.temp
DROP TABLE IF EXISTS dbo.temp2
CREATE table dbo.temp(col1 INT, col2 INT, col3 INT);
INSERT INTO temp VALUES (27,93,80),(32,84,72),(46,68,75),(38,79,73),(23,77,84);
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
-- first unpivot to key value pairs
select #colsUnpivot
= stuff((select ','+quotename(C.column_name)
from information_schema.columns as C
where C.table_name = 'temp' and
C.column_name like 'col%'
for xml path('')), 1, 1, '')
set #query
= 'SELECT ''val'' + convert(varchar, i) as id,
name,
val
INTO dbo.temp2
FROM
(
SELECT *, row_number() over (order by col1) as i
from temp
) a
UNPIVOT
(
val
FOR name IN ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
-- now pivot back
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', ' + QUOTENAME(id)
FROM (SELECT DISTINCT id FROM dbo.temp2) AS x;
SET #query = N'
SELECT name, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT id, name, val
from temp2
) AS j
PIVOT
(
SUM(val) FOR id IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) AS p;';
EXEC sp_executesql #query;
I adapted two separate scripts I had lying around, hence the two parts and the intermediate temp2 table. You can probably mash both together with a bit of elbow grease, but this should get you most of the way there.
Also adding the id (to get val1, val2 etc) dynamically means the results are sorted by col1 (val1 will have the lowest col1) but you were doing something similar in your attempt so I assume this is ok. If not, you will need to add an identity column to the data first and use that in place of the row_number()

Storing dynamic Pivot result into a temporary table in SQL Server

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 generate report using PIVOT based on date

I have two tables MasterTableTest8 and HistoricDatatest8.
create table MasterTableTest8
(ID int primary key, Name varchar(10))
insert into MasterTableTest8 values (1,'ATS')
insert into MasterTableTest8 values (2,'BTS')
CREATE TABLE HistoricDatatest8
(
ID int FOREIGN KEY REFERENCES MasterTableTest8(ID),
Name varchar(100),
ShortName varchar(10),
Reason varchar(10),
Importance varchar(10),
Noofissues int,
inserteddate datetime
)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',26,getdate()-7)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',8,getdate()+7)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',80,getdate())
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',26,getdate()-7)
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',8,getdate()+7)
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',80,getdate())
--Created and inserted two tables.
select
N.ID,
N.Name,
ShortName,
Reason,
Importance,
Noofissues,
inserteddate
INTO #TABLE
FROM HistoricDatatest8 N
JOIN MasterTableTest S ON N.ID=S.ID
--Inserting the required data in the Hash table.
--drop table #table
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CONVERT(NVARCHAR, [inserteddate], 106) + ']',
'[' + CONVERT(NVARCHAR, [inserteddate], 106) + ']')
FROM (SELECT DISTINCT [inserteddate] FROM #TABLE) PV
ORDER BY [inserteddate]
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT * FROM #TABLE
) x
PIVOT
(
count(Noofissues)
FOR [inserteddate] IN (' + #cols + ')
) p'
EXEC SP_EXECUTESQL #query
Current Result
Expected Result:
What is your expected result? Your current display shows the same current and expected result.
Are you expecting:
Date | Name | ShortName | Reason | Importance | Number of Issues|
05-Jul-16 | ATS | S| Other| High|26
12-Jul-16|BTS |S1| Other | LOW|80
After lots of R & D i got this result, might be useful to some others. if any optimized answer will be appreciated.
select * from HistoricDatatest80 order by ID
select N.ID,N.Name,ShortName,Reason,Importance,Noofissues,inserteddate INTO #TABLE FROM HistoricDatatest80 N JOIN MasterTableTest80 S ON N.ID=S.ID
--drop table #table
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols +',','')+ '['+DATEValue+']'
FROM (SELECT DISTINCT (CONVERT(NVARCHAR, [inserteddate], 106)) AS DATEValue FROM HistoricDatatest80) PV
ORDER BY DATEValue
print #cols
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT ShortName,Reason,Importance,Noofissues,(CONVERT(NVARCHAR, [inserteddate], 106)) AS DATEValue FROM #TABLE
) x
PIVOT
(
sum(Noofissues)
FOR [DATEValue] IN (' + #cols + ')
) p'
EXEC SP_EXECUTESQL #query
drop table #table

How do i pivot a table?

I have a dynamic single row Table like:
PersonId|FirstName|LastName|Address|PhoneNumber
-----------------------------------------------
1 Anuj Tamrakar NY +525418
I want to pivot this table and want an output in temp table like:
PersonalDetails|Value
----------------------
PersonId 1
FirstName Anuj
LastName Tamrakar
Address NY
PhoneNumber +525418
The first Table is a dynamic single row temp table. For this example, I have 5 columns. I may have more or less columns depending on my criteria
You actually want to UNPIVOT:
SELECT PersonalDetails, Value
FROM
(SELECT CAST([PersonId] AS VARCHAR(MAX)) AS [PersonId],
CAST([FirstName] AS VARCHAR(MAX)) AS [FirstName],
CAST([LastName] AS VARCHAR(MAX)) AS [LastName],
CAST([Address] AS VARCHAR(MAX)) AS [Address],
CAST([PhoneNumber] AS VARCHAR(MAX)) AS [PhoneNumber]
FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN
([PersonId], [FirstName], [LastName], [Address], [PhoneNumber])
) AS unpvt;
All 'to-be-unpivoted' fields have to be of the same type, hence the use of CAST.
Demo here
For a dynamic number of columns you have to use dynamic sql:
DECLARE #cols VARCHAR(MAX) = ''
DECLARE #cast_cols VARCHAR(MAX) = ''
DECLARE #qry VARCHAR(MAX)
SELECT #cols = #cols + ',[' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SELECT #cast_cols = #cast_cols + ',CAST([' + COLUMN_NAME + '] AS VARCHAR(MAX)) AS [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SET #cols = STUFF(#cols, 1, 1, '')
SET #cast_cols = STUFF(#cast_cols, 1, 1, '')
SET #qry = 'SELECT PersonalDetails, Value FROM ('
+ #cast_cols +
'FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN (' + #cols + ')
) AS unpvt'
EXEC (#qry)
If you really have a single row in the original table, then you can use a series of UNION operations to get your output:
SELECT 'PersonId' AS PersonalDetails, PersonId AS Value
FROM yourTable
UNION ALL
SELECT 'FirstName' AS PersonalDetails, FirstName AS Value
FROM yourTable
UNION ALL
SELECT 'LastName' AS PersonalDetails, LastName AS Value
FROM yourTable
UNION ALL
SELECT 'Address' AS PersonalDetails, Address AS Value
FROM yourTable
UNION ALL
SELECT 'PhoneNumber' AS PersonalDetails, PhoneNumber AS Value
FROM yourTable
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.yourTableName')
This gives you your column names. You simply insert the column names in your new table and use ``, insert into temp(PersonalDetails, Value) values(column1,select column1 from SingleRowTable

Exclude nulls from pivoted table

I have developed stored procedure as below. I would like to exclude the rows where in each inputdate colum value is null (if there is one input date which is not null, the row should stay). I have no idea how to do that. I serched the web but without any result. Appreciate Your help. Thanks.
create procedure [dbo].[sp_select_staff_time_inputs]
#startDate date,
#enddate date,
#teamid int,
#functionid int,
#servicefunctionid int
as
-- create variables, #columns = inputdates (columns of pivoted table)
DECLARE #columns NVARCHAR(2000)
declare #query nvarchar(4000)
select distinct inputdate into #temp_table_input_dates
from timeinputs
where inputdate >= #startDate and inputdate <= #enddate
order by inputdate
--select * from #temp_table_input_dates
select #columns = isnull(#columns + ',', '') + '[' + convert(varchar,convert(date,inputdate)) + ']' FROM #temp_table_input_dates
--select #columns
create table #temp_table_joins (
soeid varchar(7),
firstname varchar(50),
lastname varchar(50),
teamid int,
team varchar(50),
functionid int,
function varchar(50),
inputdate date,
noofhours float,
servicefunctionid int,
servicefunction varchar(50),
servicephaseid int,
servicephase varchar(50)
)
insert into #temp_table_joins
--select * into #temp_table_joins from
SELECT
u.SOEID, u.Firstname, u.Lastname, u.teamid,
t.team, t.functionid,
f.function,
ti.inputdate, ti.noofhours, ti.servicefunctionid,
sf.servicefunction, sf.servicephaseid,
sp. servicephase
from users u
inner join teams t on u.teamid = t.teamid
inner join functions f on t.functionid = f.functionid
inner join timeinputs ti on u.userid = ti.userid
inner join servicefunctions sf on ti.servicefunctionid = sf.servicefunctionid
inner join servicephases sp on sf.servicephaseid = sp.servicephaseid
--select * from #temp_table_joins
set #query = 'select soeid, firstname, lastname, teamid, team, functionid,
function, servicefunctionid, servicefunction, servicephaseid,
servicephase' + #columns + ' from
(select * from #temp_table_joins
) p
pivot (sum (noofhours) for inputdate in (' + #columns + ')) as asd'
--select #query
--select *, noofhours, userid from timeinputs
execute(#query)
drop table #temp_table_joins
drop table #temp_table_input_dates
GO
I'm not sure, but
DECLARE #columnscondition NVARCHAR(2000)
...
SELECT #columnscondition = isnull(#columns + ' AND ', ' WHERE ') + convert(varchar,convert(date,inputdate)) + ' IS NOT NULL ' FROM #temp_table_input_dates
...
set #query = 'select soeid, firstname, lastname, teamid, team, functionid,
function, servicefunctionid, servicefunction, servicephaseid,
servicephase' + #columns + ' from
(select * from #temp_table_joins
) p'
+ #columnscondition +
'pivot (sum (noofhours) for inputdate in (' + #columns + ')) as asd'
Perhaps, parentheses are missing in the dynamic part.
Thank You valiik.
Your solltion doesn't wok to me as expected but You inspired me to create my own.
Please see below code:
create procedure [dbo].[sp_select_staff_time_inputs]
#startDate date,
#enddate date,
#gvoteamid int,
#gvofunctionid int,
#servicefunctionid int
as
-- create variables, #columns = inputdates (columns of pivoted table)
DECLARE #columns NVARCHAR(2000)
declare #query nvarchar(4000)
DECLARE #columnscondition NVARCHAR(2000)
select distinct inputdate into #temp_table_input_dates
from timeinputs
where inputdate >= #startDate and inputdate <= #enddate
order by inputdate
--select * from #temp_table_input_dates
select #columns = isnull(#columns + ',', '') + '[' + convert(varchar,convert(date,inputdate)) + ']' FROM #temp_table_input_dates
select #columnscondition = isnull(#columnscondition + ' and ', '') + '[' + convert(varchar,convert(date,inputdate)) + '] is not null' FROM #temp_table_input_dates
--SELECT #columnscondition
--select #columns
create table #temp_table_joins (
soeid varchar(7),
firstname varchar(50),
lastname varchar(50),
gvoteamid int,
gvoteam varchar(50),
gvofunctionid int,
gvofunction varchar(50),
inputdate date,
noofhours float,
servicefunctionid int,
servicefunction varchar(50),
servicephaseid int,
servicephase varchar(50)
)
insert into #temp_table_joins
--select * into #temp_table_joins from
SELECT
u.SOEID, u.Firstname, u.Lastname, u.gvoteamid,
t.gvoteam, t.gvofunctionid,
f.gvofunction,
ti.inputdate, ti.noofhours, ti.servicefunctionid,
sf.servicefunction, sf.servicephaseid,
sp. servicephase
from users u
inner join gvoteams t on u.gvoteamid = t.gvoteamid
inner join gvofunctions f on t.gvofunctionid = f.gvofunctionid
inner join timeinputs ti on u.userid = ti.userid
inner join servicefunctions sf on ti.servicefunctionid = sf.servicefunctionid
inner join servicephases sp on sf.servicephaseid = sp.servicephaseid
--select * from #temp_table_joins
set #query = 'select soeid, firstname, lastname, gvoteamid, gvoteam, gvofunctionid,
gvofunction, servicefunctionid, servicefunction, servicephaseid,
servicephase, ' + #columns + ' from
(select * from #temp_table_joins where noofhours is not null
) p
pivot (sum (noofhours) for inputdate in (' + #columns + ')) as asd
where (' + #columnscondition +')'
--select #query
--select #query
--select *, noofhours, userid from timeinputs
execute(#query)
drop table #temp_table_joins
drop table #temp_table_input_dates
GO

Resources