SQL Server query to generate dynamic staff attendance report - sql

I have a table to store staff attendance which has the following columns:
id: int, pk
StaffName: varchar
CompanyName: varchar
isPresent: varchar
date: datetime
How do I write a query which gives attendance of a month?
Eg: Generate report for April for a company XYZ, which should looks like
StaffName 1 2 3 4 5 6 7 8 9....up to last day of month
--------------------------------------------------------------
John lenon p p p a p a a p a....
Bob Dylan a a a p p p p p a....
Keith Moon p p p p a p a p p....

That can be a little bit tricky with qynamic queries. For the table:
CREATE TABLE [dbo].[attendance](
[id] [int] NOT NULL,
[StaffName] [varchar](100) NULL,
[CompanyName] [varchar](100) NULL,
[isPresent] [char](1) NULL,
[date] [datetime] NULL,
PRIMARY KEY CLUSTERED ( [id] ASC )
)
go
The following script generates 'pivot-compatible' script with days as columns
--report params
DECLARE #month int, #year int, #lastDay int
set #month = 1
set #year = 2012
-- calculations
DECLARE #startDate datetime, #endDate datetime
SET #startDate = convert(varchar, #year) + '-' + convert(varchar, #month) + '-1'
set #endDate = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#startDate)+1,0))
set #lastDay = day(#endDate) --last day of month
print('showing data from ' + convert(varchar, #startDate) + ' to ' + convert(varchar, #endDate))
print('original report')
SELECT StaffName, isPresent, day([date]) as day FROM attendance
where [date] between #startDate and #endDate
declare #day int
set #day = 2
declare #days varchar(max)
set #days = '[1]'
WHILE (#day <= #lastDay)
BEGIN
set #days = #days + ',[' + convert(varchar, #day) + ']'
set #day = #day + 1
END
-- select #days
declare #query varchar(max)
set #query = '
SELECT StaffName, ' + #days +
'
FROM
(SELECT StaffName, isPresent, day(date) as day FROM attendance) AS SourceTable
PIVOT
(
MAX(isPresent)
FOR day IN ( ' + #days + ')' + '
) AS PivotTable;'
--select #query
print('pivoted report')
exec(#query)

You can pivot your date as column with the PIVOT functionality(here a quick and dirty example, you may check date format and order):
SELECT StaffName, [0], [1], [2], [3], [4] and so on...
FROM
(SELECT StaffName, isPresent, date FROM myTable) AS SourceTable
PIVOT
(
MAX(isPresent)
FOR date IN ([0], [1], [2], [3], [4] and so on...)
) AS PivotTable;

Related

I would like to sum a group of sums in sql

I would like get the totals for a dealer on one line. How do I go about adding that to this stored procedure?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
exec sysdba.aa_Distinguished_Dealer
*/
ALTER PROCEDURE [sysdba].[aa_Distinguished_Dealer]
AS
BEGIN
declare #baseDate datetime
declare #i int
declare #sql varchar(max)
declare #RollingDate date
declare #startOfMonth varchar(32)
set #baseDate = GETUTCDATE()
set #i = -1
if OBJECT_ID('tempdb..#rebate') is not null
drop table #rebate
create table #rebate
(
AccountId char(12),
DealerOfRecord varchar(64),
OrderTotal float,
OrderCount int,
DistinguishedDealerDate date
)
while #i > -2
begin
set #RollingDate = DATEADD(month, #i , #baseDate)
set #startOfMonth = cast(MONTH(#RollingDate) as varchar(2)) + '/1/' + cast(YEAR(#RollingDate) as CHAR(4))
set #sql = 'insert into #rebate select AccountID, DEALEROFRECORD, SUM(ORDERTOTAL) OrderTotal, COUNT(*) OrderCount, ''' + #startOfMonth + ''' DistinguishedDealerDate from sysdba.vDistinguishedDealer
where cast(convert(varchar(32), ORDERDATE, 101) as datetime) between dateadd(year, -1,''' + #startOfMonth + ''') and cast(''' + #startOfMonth + ''' as datetime)
group by AccountID, DEALEROFRECORD'
exec(#sql)
set #i = #i - 1
end
if OBJECT_ID('tempdb..#rebateResults') is not null
drop table #rebateResults
create table #rebateResults
([Rep Code] varchar(3),
[Acct. #] varchar(32),
AccountId char(12),
[Customer Name] varchar(64),
City varchar(32),
[State] varchar(32),
DDLevel varchar(32),
OrderTotal Float,
OrderCount int,
DDException varchar(2000)
)
insert into #rebateResults
select AccountId, DealerOfRecord, 'Elite', sum(OrderTotal), SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 500000 and isnull(AccountId, '') != ''
group by AccountId, DealerOfRecord
insert into #rebateResults
select AccountId, DealerOfRecord, 'Standard', sum(OrderTotal), SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 100000 and OrderTotal < 500000 and isnull(AccountId, '') != ''
group by AccountId, DealerOfRecord
select * from #rebateResults
end
As I continue to hone my SQL skills, I have begun to stop doing this in the SQL code and left it to the reporting software, but if you want it straight from the sproc... use GROUPING SETS
select CASE WHEN GROUPING (AccountId) = 1 THEN 'Total for Dealer' ELSE AccountId END AS AccountId,
DealerOfRecord,
'Elite',
sum(OrderTotal),
SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 500000 and isnull(AccountId, '') != ''
group by GROUPING SETS ((AccountId, DealerOfRecord),(DealerOfRecord))
insert into #rebateResults
select CASE WHEN GROUPING (AccountId) = 1 THEN 'Total for Dealer' ELSE AccountId END AS AccountId,
DealerOfRecord,
'Standard',
sum(OrderTotal),
SUM(OrderCount)
from #rebate
where OrderCount >= 18 and OrderTotal >= 100000 and OrderTotal < 500000 and isnull(AccountId, '') != ''
group by GROUPING SETS ((AccountId, DealerOfRecord),(DealerOfRecord))

Student Attendance Report Month-wise SQL Query

There are 3 tables -
Attendance (EnrollmentNo,SubjectCode,Date,Attendance)
Student (EnrollmentNo, RollNo),
UserDetails(EnrollmentNo,FirstName,LastName).
Now what I want is to display the attendance month-wise taking Roll No, Name, dates as column and Student.RollNo, UserDetails.FirstName, UserDetails.LastName, Attendance.Attendance as the data for the columns respectively.
But the problem I am facing is how to generate date columns dynamically and put the attendance data in the respective date column.
Input - Startdate and Enddate
Expected Output -
-------------------------------------------------------
| Roll No | Name | 01-09-2018 | 01-12-2018|
-------------------------------------------------------
| 15 | Suyash Gupta | 1 | 0 |
-------------------------------------------------------
| 24 | Himanshu Shukla | 2 | 2 |
-------------------------------------------------------
| 32 | Dhruv Raj Sirohi | 1 | 1 |
-------------------------------------------------------
This is my approach -
DECLARE #startdate date
DECLARE #enddate date
SET #startdate = convert(date,'01-09-2018')
SET #enddate = convert(date,'01-12-2018')
;with cte (#startdate, #enddate) as /*I don't know how to pass my date range
in cte() as this takes table column*/
(
select 1
union all
select dateadd(dd, 1, startdate)
from cte
where startdate <= enddate
)
select c.startdate
into #tempDates
from cte c
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10),
startdate, 120))
from #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D
left join Attendance A
on D.startdate = A.Date
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
execute(#query)
you have some issues with your code, look at the differences in my code:
DECLARE #startdate date = '20180109';
DECLARE #enddate date = '20180112';
DECLARE #cols as varchar(2000);
DECLARE #query as varchar(MAX);
WITH cte (startdate)
AS
(SELECT
#startdate AS startdate
UNION ALL
SELECT
DATEADD(DAY, 1, startdate) AS startdate
FROM cte
WHERE startdate < #enddate)
SELECT
#cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(CONVERT(CHAR(10),
startdate, 120))
FROM cte
FOR XML PATH (''), TYPE)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D
left join Attendance A
on D.startdate = A.Date
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXECUTE (#query)
Do you mean something like this:
DECLARE #StartDate AS DATETIME, #EndDate AS DATETIME
SET #StartDate='2018-01-01'
SET #EndDate='2018-01-10'
SELECT Student.RollNo, Student.FirstName, Student.LastName, Attendance.Date
FROM Attendance,Student,UserDetails
WHERE Attendance.EnrollmentNo=Student.EnrollmentNo
AND UserDetails.EnrollmentNo=Student.EnrollmentNo
AND Attendance.[Date] between #StartDate and #EndDate
UPDATE
Based on what you said in the question maybe the following code is what you need:
SELECT Student.RollNo, Student.FirstName, Student.LastName,
STUFF((SELECT ','+CAST([DATE] AS VARCHAR(30))
FROM Attendance
WHERE Attendance.EnrollmentNo=Student.EnrollmentNo
AND Attendance.[Date] between #StartDate AND #EndDate
FOR XML PATH('')
), 1, 1, '') Dates
FROM Student,UserDetails
WHERE UserDetails.EnrollmentNo=Student.EnrollmentNo
This is running code and giving me the desired output. I want to thank Lobo, who corrected me, and everyone else who had put in the efforts to help me. Thank you all and stackoverflow who provided me the platform to query the problem I was facing.
DECLARE #startdate date = '20180109';
DECLARE #enddate date = '20180112';
DECLARE #cols as varchar(2000);
DECLARE #query as varchar(MAX);
WITH cte (startdate)
AS
(SELECT
#startdate AS startdate
UNION ALL
SELECT
DATEADD(DAY, 1, startdate) AS startdate
FROM cte
WHERE startdate < #enddate
)
select c.startdate
into #tempDates
from cte c
SELECT
#cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(CONVERT(CHAR(10),
startdate, 120))
FROM #tempDates
FOR XML PATH (''), TYPE)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D,Attendance A, Student S, UserDetails U
where D.startdate = A.Date and A.EnrollmentNo=S.EnrollmentNo and A.EnrollmentNo=U.userID
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXECUTE (#query)
drop table #tempDates

Find Count With Pivot Data SQL Server

I have been displaying Day Wise Attendance Data with Pivot SQL.
declare #startdate datetime = '2016-09-26'
declare #enddate datetime = '2016-10-01'
declare #CompanyID int = 1
DECLARE #COLUMN VARCHAR(MAX), #SQL NVARCHAR(MAX);
SET #COLUMN = N'';
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT #COLUMN += N', T.' + QUOTENAME(DateRanges) FROM (SELECT CAST(CONVERT(DATE, T.DateToCheck) AS VARCHAR(10)) AS DateRanges FROM #DATERANGE T group by T.DateToCheck) AS A;
SET #SQL = '
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT *
FROM (
SELECT E.FirstName, E.LastName, E.Email, T.DateToCheck, COALESCE(A.val, L.val, H.val, ''Absent'') val
FROM AspNetUsers E
CROSS APPLY (
SELECT DateToCheck FROM #DATERANGE
) T--(DateToCheck)
LEFT JOIN (SELECT ''Holiday'' val, HolidayDate, CompanyID FROM Holidays) H ON H.HolidayDate = T.DateToCheck AND H.CompanyID = #CompanyID
LEFT JOIN (SELECT ''In : '' + CONVERT(VARCHAR, MIN(AttendanceDateTime), 108) + '' / Out : '' + CONVERT(VARCHAR, MAX(AttendanceDateTime), 108) val, CAST(AttendanceDateTime As DATE) As AttendanceDate, UserID FROM Attendances GROUP BY CAST(AttendanceDateTime As DATE), UserID) A ON A.AttendanceDate = T.DateToCheck AND A.UserID = E.Id
LEFT JOIN (SELECT ''Leave'' val, LeaveDate, UserID FROM LeaveApplications) L ON L.LeaveDate = T.DateToCheck AND L.UserID = E.Id
WHERE E.CompanyID = #CompanyID
) T
PIVOT (MAX(val) FOR DateToCheck IN (' + STUFF(REPLACE(#COLUMN, ', T.[', ',['), 1, 1, '') + ')) P';
EXEC sp_executesql #SQL, N'#startdate DATE, #enddate DATE, #CompanyID INT', #startdate, #enddate, #CompanyID
And below is the result set of how it's now
Now I wish to add more field to the above SQL to display counts like PresentCount, AbsentCount, HolidayCount and LeaveCount
I have already written a SQL where I could easily display these counts but, I'm unable to make it work with the above PIVOT SQL.
So in this case, the result for first row would be PresentCount = 0, AbsentCount = 6, HolidayCount = 0 and LeaveCount = 0. For Row 2 it would be PresentCount = 4, AbsentCount = 2, LeaveCount and HolidayCount both is 0.

How to create Temp Table with month columns based on date parameters?

I have a stored procedure that accepts two Dates. In my stored procedure, I need to create a temp table with the months in between the two dates as columns.
For example,
If the user passes in
1/1/2016 , 8/1/2016
I need a temp table with the columns:
January February March April May June July August
How could I create this type of temp table with columns created in this manner? With the columns being based on the two dates passed in?
The following script should get you started (and almost there):
declare #start_date DATE = '20160101'
declare #end_date DATE = '20160801'
;WITH CTE AS
(
SELECT #start_date AS cte_start_date, DATENAME(month, #start_date) AS Name,
CAST(' ALTER TABLE #myTemp ADD ' + DATENAME(month, #start_date) + ' INT ' + CHAR(13) + CHAR(10) AS VARCHAR(8000)) AS SqlStr
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date), DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) AS Name,
CAST(SqlStr + ' ALTER TABLE #myTemp ADD ' + DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) + ' INT ' + CHAR(13) + CHAR(10) AS VARCHAR(8000))
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT cte_start_date, Name, SqlStr
FROM CTE
Using a recursive-CTE it generates a loop between start and end date, and for each month it computes its string representation and also creates a alter script to add the columns to a temporary table.
The CTE computes the SQL script gradually, so that the final script is on the last line.
Try This ....
declare #start_date DATE = '20160101'
declare #end_date DATE = '20160801'
;WITH CTE AS
(
SELECT #start_date AS cte_start_date, DATENAME(month, #start_date) AS NAME , 0 AS Coun
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date), DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) AS NAME , 0 AS Coun
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT Coun,Name
INTO #tmp1
FROM CTE
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + Name
from #tmp1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + ' from
(
select Coun,Name
from #tmp1
) x
pivot
(
MAX(Coun)
for Name in (' + #cols + ')
) p '
execute(#query);
DROP TABLE #tmp1
It Will Return OutPut Like your expected output .......

Date functions in Stored Procedure

Overview : I want to show the weekly result by input parameters startdate and enddate. I am getting this result quite well. But the problem here is, When i want start date from 28/08/2015 from end date 04/09/2015 am getting 28, 29, 30, 31, 01, 02, 03, 04 from same month(august). Expected result should be 28, 29, 30, 31 from august and 01, 02, 03, 04 from september.
Help me to overcome this problem. Below is my code
ALTER PROCEDURE [dbo].[usp_Get_TimesheetDetails]
#UserID int, #startdate datetime, #enddate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #intStartDate int
declare #intEndDate int, #diff int
declare #strMonth varchar(50)
Select #intStartDate = DATEPART(day, #startDate)
Select #intEndDate = DATEPART(day, #endDate)
select #strMonth = DATENAME(MONTH, GETDATE())
Declare #temptable table (num date )
Declare #columns varchar(max)
DECLARE #sqlText nvarchar(1000);
DECLARE #startnum INT = #intStartDate-1
DECLARE #endnum INT = #intEndDate
select #diff = DATEDIFF(MONTH, #startdate, #enddate)
;WITH gen AS (
SELECT #startdate AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM #temptable t)
if(#startnum < 10)
BEGIN
SET #sqlText = N'SELECT ' + STUFF(REPLACE(#columns,',','],['),1,3,'') + ']' + ' FROM dbo.timesheet where month ='''+ #strMonth+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')'
print #sqlText
END
else if(#startnum >= 10)
BEGIN
SET #sqlText = N'SELECT ' + STUFF(REPLACE(#columns,',','],['),1,4,'') + ']' + ' FROM dbo.timesheet where month ='''+ #strMonth+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')'
END
print #sqlText
Exec (#sqlText)
end
end
Edited : I tried with if else condition like, if(monthdifference is equal to 0)
else(monthdifference is greater than 0). But not getting expected result.
try this
Declare
#StartDate datetime='2015/08/28',
#EndDate datetime='2015/09/04'
;WITH sample AS (
SELECT CAST(#StartDate AS DATETIME) AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM sample s
WHERE DATEADD(dd, 1, dt) <= CAST(#EndDate AS DATETIME))
SELECT *
FROM sample
output is :
2015-08-28 00:00:00.000
2015-08-29 00:00:00.000
2015-08-30 00:00:00.000
2015-08-31 00:00:00.000
2015-09-01 00:00:00.000
2015-09-02 00:00:00.000
2015-09-03 00:00:00.000
2015-09-04 00:00:00.000
Original Link : https://stackoverflow.com/a/3946151/3465753
Make sure you declared startdate as well as enddate in dynamic query
The main Ideas are:
You don't need to use STUFF. Just select dates from DATEADD(DAY,1,#startdate)
You should get dates twise if DATENAME(MONTH, #startdate)!=DATENAME(MONTH, #enddate). First time from startdate to end of months. Second time from start of second month to enddate.
My (checked) script.
ALTER PROCEDURE [dbo].[usp_Get_TimesheetDetails]
#UserID int, #startdate datetime, #enddate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #columns varchar(max);
DECLARE #sqlText nvarchar(1000);
Declare #temptable table (num date );
WITH gen AS (
SELECT DATEADD(DAY,1,#startdate) AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
and DATEADD(DAY,1,num) < dateadd(month,datediff(month,0,#enddate),0)
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #temptable t)
SET #sqlText = N'SELECT [' + REPLACE(#columns,',','],[') + ']' + ' FROM dbo.timesheet where month ='''+ DATENAME(MONTH, #startdate)+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')';
print #sqlText;
IF DATENAME(MONTH, #startdate)!=DATENAME(MONTH, #enddate)
BEGIN
delete from #temptable;
WITH gen AS (
SELECT dateadd(month,datediff(month,0,#enddate),0) AS num
UNION ALL
SELECT DATEADD(DAY,1,num) FROM gen
WHERE DATEADD(DAY,1,num) <= #enddate
)
insert into #temptable SELECT num FROM gen
option (maxrecursion 10000)
set #columns=
(SELECT distinct
STUFF((SELECT ',' + CAST( DATEPART(DAY, num) as varchar(100)) [text()]
FROM #temptable
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #temptable t)
SET #sqlText = N'SELECT [' + REPLACE(#columns,',','],[') + ']' + ' FROM dbo.timesheet where month ='''+ DATENAME(MONTH, #enddate)+''' and [Task ID] in(select TaskID from ManageTasks where TeamMemberUserID ='+ Cast(#UserID AS VARCHAR(max)) +')';
print #sqlText
end
end
You might find pivot/unpivot to be more robust. Certainly your table design is not ideal. (I pared down the number of columns for demonstration purposes.)
create table dbo.timesheet (
[month] varchar(12) not null,
[1] int null, [2] int null, [3] int null,
[28] int null, [29] int null, [30] int null, [31] int null
);
declare #startDate date = '20160628';
declare #endDate date = '20160703';
insert into dbo.timesheet ([month], [1], [2], [3], [28], [29], [30], [31])
values ('June', 1, 2, 3, 4, 5, 6, null), ('July', 8, 9, 10, 11, 12, 13, 14);
with hrs as (
select
hrs,
dy,
dateadd(
month,
case [month]
when 'January' then 1 when 'February' then 2 when 'March' then 3
when 'April' then 4 when 'May' then 5 when 'June' then 6
when 'July' then 7 when 'August' then 8 when 'September' then 9
when 'October' then 10 when 'November' then 11 when 'December' then 12
end,
dateadd(year, year(getdate()) - 2000, dateadd(day, dy - 1, '19991201'))
) as dt
from
(select [month], [1], [2], [3], [28], [29], [30], [31] from dbo.timesheet) t
unpivot (hrs for dy in ([1], [2], [3], [28], [29], [30], [31])) as upvt
)
select datename(month, dt), [1], [2], [3], [28], [29], [30], [31]
from hrs pivot (min(hrs) for dy in ([1], [2], [3], [28], [29], [30], [31])) as pvt
where dt between #startDate and #endDate;