SQL Report Query

Hi  

I will start with my end result required.

So I want to get a query like
                                   ActualHoursWorked      HoursToWork     Variance
WendyOSBORNE                        100                         120                 20
YvonneDOLAN                           90                           100                 10
Sandra AADAIR                          110                         140                 30


I have a timesheets table (with the only the columns relating to my question below) which holds timesheet information and hours actually worked.

 TABLE [dbo].[TIMESHEET](
        [DATE] [datetime] NULL,
      [TIME] [decimal](4, 2) NOT NULL,
      [IdVolNow]  as varchar(50)

sample data
RefId      DATE      TIME      IdVolNow
28521      2011-02-28 00:00:00.000      1.25      FidelmaGLASS
28591      2011-02-28 00:00:00.000      0.50      FidelmaGLASS
40030      2011-02-28 00:00:00.000      4.75      FidelmaGLASS
50046      2012-02-22 00:00:00.000      8.00      NicciWILSON
54758      2011-06-03 00:00:00.000      2.50      RuthMULHOLLAND
62266      2011-01-03 00:00:00.000      4.00      WendaGRAY W
62290      2011-01-03 00:00:00.000      7.00      Lyne GGREENWOOD
62291      2011-01-04 00:00:00.000      7.00      Lyne GGREENWOOD
62292      2011-01-07 00:00:00.000      7.00      Lyne GGREENWOOD


I have another table which specifies the days and hours that an employee should be working.

sample data
ID      Date                      UserName      Hours
365      2013-01-01      KathyCORBETT      6
366      2013-01-02      KathyCORBETT      6
367      2013-01-03      KathyCORBETT      6
368      2013-01-04      KathyCORBETT      6
369      2013-01-07      KathyCORBETT      6
370      2013-01-08      KathyCORBETT      6

I have a staff table with staff names
WendyOSBORNE
YvonneDOLAN
Sandra AADAIR


First of all i have the query that I want partially working but a bit slow.  Im sure there is a better way to do what I want that the way I describe below.

What I did


I created a Function for Total Hours To Work,  referred to here as capacity.

ALTER FUNCTION [dbo].[ufn_GetCapacity]
(
@UserName    varchar(50),
@Month    varchar(50),
@Year int
 )
RETURNS Int
BEGIN
 DECLARE @Capacity int
Select @Capacity = (SELECT     Sum(Hours) as TotalHours
FROM         WorkDays WHERE
DATENAME(month, [Date]) = @Month
AND YEAR([Date]) = @Year
AND UserName=@UserName)

Return @Capacity


created a function for total hours actually worked
ALTER FUNCTION [dbo].[ufn_GetWorkedHours]
(
@UserName    varchar(50),
@Month    varchar(50),
@Year int
 )
RETURNS Int
BEGIN
DECLARE @WorkedHours int
Select @WorkedHours = (SELECT Sum([TIME]) as Total FROM [Timesheets].[dbo].[TIMESHEET]
                                    WHERE [IdVolNow] = @Username
                                    AND Year([Date]) = @Year
                                    AND DATENAME(month, [Date]) = @Month)

Return @WorkedHours

END


I can now run a query like below.  Which does actually work but
1)  is a bit slow about 15sec
2)  I still have to work the variance which im sure will add another 10 secs if i continue using this method.

SELECT [FirstName]
      ,[SURNAME]
      , dbo.ufn_GetCapacity([FirstName] + [SURNAME], @Month, @Year)  as Capcaity
      , dbo.ufn_GetWorkedHours([FirstName] + [SURNAME], @Month, @Year) as WorkedHours
   FROM [Timesheets].[dbo].[Staff]
  WHERE [current] = 1
  ORDER  BY [FirstName]
      ,[SURNAME]
LVL 3
Kevin RobinsonPrivate VB.NET ContractorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

expert_dharamCommented:
Create  stored procedure to store this query..
Execution time should improve..
0
DOSLoverCommented:
Assuming the tables have right indexes based, a join may be faster that UDF:
SELECT  s.FirstName
      , s.SURNAME
        , Year(t.date)
        , DATENAME(month, t.date)
      , Sum(w.Hours) as Capcaity
      , SUM(t.time) as WorkedHours
        , Sum(w.Hours) - SUM(t.time) as wVariance
   FROM Timesheets t
   LEFT JOIN Staff s ON s.UserName = t.idVolNow
   LEFT JOIN workdays w on w.UserName = t.idVolNow and Year(t.date)=Year(w.date) and DATENAME(month, w.date) = DATENAME(month, t.date)
  WHERE [current] = 1
  GROUP BY s.FirstName, s.SURNAME, Year(t.date), DATENAME(month, t.date)
  ORDER BY s.FirstName, s.SURNAME, Year(t.date), DATENAME(month, t.date)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Kevin RobinsonPrivate VB.NET ContractorAuthor Commented:
Hey DOSLover this looks good except the Staff Members that have not entered any timesheet info are not appearing in the query.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

Anthony PerkinsCommented:
except the Staff Members that have not entered any timesheet info are not appearing in the query.
If current is part of Staff Or workdays it cannot be in the WHERE clause, it has to be in the JOIN or it will treat the OUTER  JOIN as an INNER JOIN and you will not return all the rows.
0
DOSLoverCommented:
The statement can be tweaked based on such requirement. For example, say, we want to make Staff as the primary driving table - pull data for all users from Staff table whether they have workdays defined or have entered timesheet info or not. To acperkins question abt 'current=1' - I assumed it is there to retrieve current row (in case historical records are also stored) - or else that condition can be dropped.

  SELECT  s.FirstName
      , s.SURNAME
        , Year(w.date)
        , DATENAME(month, w.date)
      , Sum(w.Hours) as Capcaity
      , SUM(t.time) as WorkedHours
        , Sum(w.Hours) - SUM(t.time) as wVariance
   FROM Staff s
   LEFT JOIN workdays w on w.UserName = s.UserName
   LEFT JOIN Timesheet t ON t.UserName = w.UserName and Year(t.date)=Year(w.date) and DATENAME(month, t.date) = DATENAME(month, w.date)
  WHERE [current] = 1
  GROUP BY s.FirstName, s.SURNAME, Year(w.date), DATENAME(month, w.date)
  ORDER BY s.FirstName, s.SURNAME, Year(w.date), DATENAME(month, w.date)
0
Kevin RobinsonPrivate VB.NET ContractorAuthor Commented:
Hi that last query didnt quite work but I ended going with this, ( A Union Join).  Hopefully you dont think it is too messy :).  It works anyway.  Thank for your excellent help.

ALTER PROCEDURE [dbo].[sp_GetFullTimeStaffReport]
(
@Month      varchar(30),
@YEAR      int
)
AS
SELECT     TIMESHEET.IdVolNow as UserName,
dbo.ufn_GetCapacity(TIMESHEET.IdVolNow, @Month, @YEAR) AS Capacity,
SUM(TIMESHEET.TIME) AS HoursWorked,
SUM(TIMESHEET.TIME) - dbo.ufn_GetCapacity(TIMESHEET.IdVolNow, @Month, @YEAR) AS Variance
FROM         TIMESHEET LEFT JOIN
Staff ON TIMESHEET.IdVolNow = Staff.UserName
WHERE     (YEAR(TIMESHEET.DATE) = @YEAR) AND (DATENAME(month, TIMESHEET.DATE) = @Month)
AND staff.[current] = 1
AND IsFullTime = 1
GROUP BY TIMESHEET.IdVolNow
UNION
SELECT   UserName,
dbo.ufn_GetCapacity(UserName, @Month, @YEAR) AS Capacity,
0 AS HoursWorked,  dbo.ufn_GetCapacity(UserName, @Month, 2013) AS Variance
FROM         Staff
WHERE Staff.USername NOT IN (SELECT IdVolNow FROM TIMESHEET WHERE     (YEAR(TIMESHEET.DATE) = @YEAR) AND (DATENAME(month, TIMESHEET.DATE) = @Month) )
AND staff.[current] = 1
AND IsFullTime = 1
ORDER BY UserName
0
Kevin RobinsonPrivate VB.NET ContractorAuthor Commented:
Thanks
0
Anthony PerkinsCommented:
I suspect you may have overlooked my previous comment so I will try it again:

This:
FROM         TIMESHEET LEFT JOIN
Staff ON TIMESHEET.IdVolNow = Staff.UserName
WHERE     (YEAR(TIMESHEET.DATE) = @YEAR) AND (DATENAME(month, TIMESHEET.DATE) = @Month)
AND staff.[current] = 1

Is exactly the same as this:
FROM         TIMESHEET INNER JOIN
Staff ON TIMESHEET.IdVolNow = Staff.UserName
WHERE     (YEAR(TIMESHEET.DATE) = @YEAR) AND (DATENAME(month, TIMESHEET.DATE) = @Month)
AND staff.[current] = 1

If you really want a LEFT JOIN then you should code it correctly as in:
FROM         TIMESHEET LEFT JOIN
Staff ON TIMESHEET.IdVolNow = Staff.UserName AND staff.[current] = 1
WHERE     (YEAR(TIMESHEET.DATE) = @YEAR) AND (DATENAME(month, TIMESHEET.DATE) = @Month)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server 2008

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.