Solved

SQL query to summarize items per month

Posted on 2016-11-23
5
89 Views
Last Modified: 2016-12-28
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
Comment
Question by:DrakeCA
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
5 Comments
 
LVL 29

Expert Comment

by:Pawan Kumar
ID: 41899988
* - 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
 

Author Comment

by:DrakeCA
ID: 41900572
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
 
LVL 69

Accepted Solution

by:
Scott Pletcher earned 500 total points
ID: 41901748
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
 

Author Closing Comment

by:DrakeCA
ID: 41901914
This does exactly what I need it to.  Thanks so much for your assistance!
0
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 41901916
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

Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

How to leverage one TLS certificate to encrypt Microsoft SQL traffic and Remote Desktop Services, versus creating multiple tickets for the same server.
A Stored Procedure in Microsoft SQL Server is a powerful feature that it can be used to execute the Data Manipulation Language (DML) or Data Definition Language (DDL). Depending on business requirements, a single Stored Procedure can return differe…
Using examples as well as descriptions, and references to Books Online, show the different Recovery Models available in SQL Server and explain, as well as show how full, differential and transaction log backups are performed
Via a live example, show how to backup a database, simulate a failure backup the tail of the database transaction log and perform the restore.

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question