• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 130
  • Last Modified:

SQL query to summarize items per month

We have a current SQL query which summarizes the hours worked by a particular branches staff.  Rather then running this report every month I would like to create a new report which automatically calculates the totals for each month, over an 18 month period.

EXAMPLE:

Current query has TOTAL HOURS -- EMPLOYEE FIRST NAME -- EMPLOYEE LAST NAME as headers.

I would like to see: EMPLOYEE FIRST - EMPLOYEE LAST - 2015JAN - 2015FEB...2016JAN - 2016FEB...

The current query is listed below:

use DB1
go
select      sum(timesheet_orders.no_of_hours) as TotalHours,
            user_profile.first_name, user_profile.last_name
From orders
            Inner Join timesheet_orders on orders.order_id = timesheet_orders.order_id
            Inner Join timesheet_header on timesheet_orders.timesheet_number = timesheet_header.timesheet_number
            Inner Join client_organization on orders.group_id = client_organization.group_id
            Inner Join user_profile on timesheet_header.contractor_id = user_profile.user_id

where timesheet_header.start_date >= dateadd(mm,-1,getdate())
             and timesheet_orders.status = 'P' and orders.office_id = '2601'

group by user_profile.first_name, user_profile.last_name

order by TotalHours desc


I know another query we created uses the DATEPART command but I am unsure of the proper syntax to use something like this with our current query.

Any assistance would be appreciated.
0
DrakeCA
Asked:
DrakeCA
  • 2
  • 2
1 Solution
 
Pawan KumarDatabase ExpertCommented:
* - Added MS SQL Servers as Topic.

try..
use DB1
go
select      sum(timesheet_orders.no_of_hours) as TotalHours, 
            user_profile.first_name, user_profile.last_name,
			YEAR(timesheet_header.start_date) + ' ' + LEFT(DATENAME(MONTH,timesheet_header.start_date),3) YearMonth 
From orders
            Inner Join timesheet_orders on orders.order_id = timesheet_orders.order_id
            Inner Join timesheet_header on timesheet_orders.timesheet_number = timesheet_header.timesheet_number
            Inner Join client_organization on orders.group_id = client_organization.group_id
            Inner Join user_profile on timesheet_header.contractor_id = user_profile.user_id

where timesheet_header.start_date >= dateadd(mm,-1,getdate()) 
      and timesheet_orders.status = 'P' and orders.office_id = '2601'

group by user_profile.first_name, user_profile.last_name, YEAR(timesheet_header.start_date), MONTH(timesheet_header.start_date)

order by TotalHours desc

Open in new window

0
 
DrakeCAAuthor Commented:
Thanks for the input.  Looks interesting.

When I try running it I get the following error:

"Msg 8120, Level 16, State 1, Line 1
Column 'timesheet_header.start_date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."


Any suggestions?
0
 
Scott PletcherSenior DBACommented:
The easiest way to get the specific "yyyyMth" column names you want is to create the table with generic column names and rename them to specific names after loading the table.  Here's code to do all that; be sure to finish the code for all 18 months first before running.

if object_id('tempdb.dbo.#TotalHours') is not null
    drop table #TotalHours

--use generic column names for monthly totals, will be renamed later to exact yyyyMth name.    
select      
            user_profile.first_name, user_profile.last_name,
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 18, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 17, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_18MonthsAgo,
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 17, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 16, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_17MonthsAgo,
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 16, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 15, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_16MonthsAgo,
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 15, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 14, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_15MonthsAgo,
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 14, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 13, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_14MonthsAgo,
            --,...fill in the code for 13Months thru 02Months,using the code pattern shown...
            sum(case when timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 01, 0) and
                          timesheet_header.start_date < dateadd(month, datediff(month, 0, getdate()) - 00, 0)
                     then timesheet_orders.no_of_hours else 0 end) as TotalHours_01MonthsAgo,
            sum(timesheet_orders.no_of_hours) as TotalHours_AllMonths

Into #TotalHours
From orders
            Inner Join timesheet_orders on orders.order_id = timesheet_orders.order_id
            Inner Join timesheet_header on timesheet_orders.timesheet_number = timesheet_header.timesheet_number
            Inner Join client_organization on orders.group_id = client_organization.group_id
            Inner Join user_profile on timesheet_header.contractor_id = user_profile.user_id

where timesheet_header.start_date >= dateadd(month, datediff(month, 0, getdate()) - 18, 0)
             and timesheet_orders.status = 'P' and orders.office_id = '2601'

group by user_profile.first_name, user_profile.last_name

order by TotalHours_AllMonths desc


--rename generic column names to exact yyyyMth name.    
declare @column_name_original varchar(100)
declare @column_name_original_month_offset int
declare @column_name_yyyyMth varchar(7)
declare @month_number int
declare @timesheet_month date

set @column_name_original = 'dbo.#TotalHours.TotalHours_18MonthsAgo'
set @column_name_original_month_offset = PATINDEX('%[0-9]%', @column_name_original)
set @month_number = 18
while @month_number > 0
begin
    set @timesheet_month = dateadd(month, datediff(month, 0, getdate()) - @month_number, 0)
    set @column_name_original = stuff(@column_name_original, @column_name_original_month_offset,
        2, right('0' + cast(@month_number as varchar(2)), 2))
    set @column_name_yyyyMth = cast(year(@timesheet_month) as varchar(4)) + left(datename(month, @timesheet_month), 3)
    exec tempdb.sys.sp_rename @column_name_original, @column_name_yyyyMth, 'COLUMN'
    set @month_number = @month_number - 1    
end /*while*/


select *
from #TotalHours
order by TotalHours_AllMonths desc, last_name, first_name
0
 
DrakeCAAuthor Commented:
This does exactly what I need it to.  Thanks so much for your assistance!
0
 
Scott PletcherSenior DBACommented:
You're welcome!  The totalling technique is very helpful once you see it used and get used to it.  Btw, the column renaming code actually took more time than the totals query itself :-) .
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now