You could, but honestly I prefer to do as much data prep as possible back on the server. That way I can manipulate sometimes without having to re-write reports, and try to take control over the volume of data being bandied about, and, trying to take advantage of anything the Server might be able to offer in terms of performance.
In this case, I would probably create a view and then simply select from the view.
A view is like a virtual table. It is really more like a stored query, with the advantage that you can refer to a view just like any other table. It doesnt hold data itelf, but knows where to get it from, and the Server does too so will try to use all the performance stats from the underlying tales when looking at query plans.
Creating the view is a once off process, once there, use it just like a table. Any updates to data is done on the actual tables, and is instantaneously reflected in the view. They are pretty cool things and ideally suited to these types of cases where the query is a bit involved / a bit unwieldy to use directly.
First time in, you "create" the view, subsequent changes are done using "alter"
-- OK, lets create the view.... naming conventions can be important and it is not uncommon to find the few few characters reflecting the type of database object.
-- In this case, using the prefix VW to denote VIEW
CREATE VIEW vw_Jobs_Budget_vs_Actual AS
SELECT job_no
, cost_code_no
, sum(Labor_Budget) as labor_budget
, sum(Material_Budget) Material_Budget
, sum(Subcontract_Budget) Subcontract_Budget
, sum(Mileage_Budget) Mileage_Budget
, sum(Burden_Budget) Burden_Budget
, sum(Labor_cost) Labor_cost
, sum(Material_cost) Material_cost
, sum(Subcontract_cost) Subcontract_cost
, sum(Mileage_cost) Mileage_cost
, sum(Burden_cost) Burden_cost
, sum(total_budget) as total_budget
, sum(total_cost) as total_cost
, sum(total_budget) - sum(total_cost) as variance
FROM (
select job_no
, cost_code_no
, case when cost_class_no = 1 then orig_est_dollars else 0 end as Labor_Budget
, case when cost_class_no = 2 then orig_est_dollars else 0 end as Material_Budget
, case when cost_class_no = 3 then orig_est_dollars else 0 end as Subcontract_Budget
, case when cost_class_no = 4 then orig_est_dollars else 0 end as Mileage_Budget
, case when cost_class_no = 6 then orig_est_dollars else 0 end as Burden_Budget
, orig_est_dollars as total_budget
, 0.00 as Labor_cost
, 0.00 as Material_cost
, 0.00 as Subcontract_cost
, 0.00 as Mileage_cost
, 0.00 as Burden_cost
, 0.00 as total_cost
From Job_Budgets
UNION ALL
select job_no
, cost_code_no
, 0.00 as Labor_budget
, 0.00 as Material_budget
, 0.00 as Subcontract_budget
, 0.00 as Mileage_budget
, 0.00 as Burden_budget
, 0.00 as total_budget
, case when cost_class_no = 1 then cost else 0 end as Labor_Cost
, case when cost_class_no = 2 then cost else 0 end as Material_Cost
, case when cost_class_no = 3 then cost else 0 end as Subcontract_Cost
, case when cost_class_no = 4 then cost else 0 end as Mileage_Cost
, case when cost_class_no = 6 then cost else 0 end as Burden_Cost
, cost as total_cost
From Job_History
) src
GROUP BY Job_No, cost_code_no
-- ORDER BY Job_No, cost_code_no
-- dont include ORDER BY in a view unless you also use the TOP qualifier
-- just remember to do your own order by when selecting from the view.
GO
-- Now that has been done...
-- We can start using it. Referring to it just like any other table (pretty much... we can select, join, use where, use order by, aggregate etc etc)
select * from vw_Jobs_Budget_vs_Actual
-- and that is what you now use in your crystal reports as your data source...