0

I've built a query that uses a typical header/detail set of tables to report on records from the header table but provides aggregated data per header record from various types on the detail table.

To get around the grouping issues I created a view to join against that does all the aggregation based on the invoice key.

CREATE OR REPLACE VIEW TransactDetailSummary_V AS
  SELECT
td.invoice
, SUM(CASE WHEN td.TaxCollected1 + td.TaxCollected2 + td.TaxCollected3 <> 0 AND td.Type NOT IN (9,13) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as taxable_sales
, SUM(CASE WHEN td.TaxCollected1 + td.TaxCollected2 + td.TaxCollected3 = 0 AND td.Type NOT IN (9,13) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as nontaxable_sales
, SUM(CASE WHEN td.Type IN (8,18) THEN td.Amount ELSE 0 END) as total_taxes
, SUM(CASE WHEN td.Type IN (15,16,26) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) AS returns
, SUM(CASE WHEN td.Type IN (24) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) AS trade_ins
, SUM(CASE WHEN td.Type IN (9,13,22) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) AS payments
, SUM(CASE WHEN td.Type = 2 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as part_sales
, SUM(CASE WHEN td.Type = 3 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as serial_sales
, SUM(CASE WHEN td.Type = 15 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as part_returns
, SUM(CASE WHEN td.Type = 16 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as serial_returns
, SUM(CASE WHEN td.Type = 10 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as misc_charges
, SUM(CASE WHEN td.Type = 6 THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as labor_charges
, SUM(CASE WHEN td.Type IN (4,5,11) THEN ROUND(td.Quantity * td.Amount, 2) ELSE 0 END) as rental_sales
FROM transactdetail td
GROUP BY td.Invoice;

Then in the report query I join to the details view using the invoice key.

SELECT
  'Customer Invoices COMPLETED' as section_title
  , CAST(th.Invoice as UNSIGNED) as Invoice
  , th.DateInvoice as invoice_date
  , th.DateApply as completed_date
  , th.orderstatus as status
  , th.customername as customer_name
  , tdv.taxable_sales
  , tdv.nontaxable_sales
  , tdv.total_taxes
  , tdv.returns
  , tdv.trade_ins
  , tdv.payments
  , tdv.part_sales
  , tdv.serial_sales
  , tdv.part_returns
  , tdv.serial_returns
  , tdv.misc_charges
  , tdv.labor_charges
  , tdv.rental_sales
FROM transactheader th
JOIN TransactDetailSummary_V tdv ON tdv.Invoice = th.Invoice
WHERE th.DateApply BETWEEN '2013-04-15' AND '2013-04-15'
  AND th.OrderStatus IN ('Complete','Backorder')
  AND th.Type = 1
  AND th.Created = 'invoice'
ORDER BY 1;

In this example I get back 13 header records with the aggregate data, cool! But I started to dive into how much work the engine was doing and I found something startling.

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL                 75609   
1   PRIMARY th  ref Invoice_Key,Type_Key,Status_Key Invoice_Key 20  tdv.invoice,const   10  Using where
2   DERIVED td  ALL                 350477  Using temporary; Using filesort

The explain shows that every row is being read in the details table to provide aggregates for the 13 headers I care about. I understand that the view is materializing and then filtering based on the join.

The question is, is there a way to do this so that it only reads the details for the 13 invoices I care about? I imaging a joined subquery would work the same way unless I can possibly correlate it?

Thanks in advance for any help.

Jeremie
  • 41
  • 1
  • 6
  • Placing the select query from the view in as a joined subquery yields the exact same explain plan. – Jeremie May 30 '13 at 16:30
  • Interesting question. I wondered if a view can be passed a parameter to limit its results - this is the answer on that one! http://stackoverflow.com/questions/1687279/can-we-pass-parameter-to-a-view-in-sql ... good luck anyway – AjV Jsy May 30 '13 at 19:54
  • DB2 behaves the same way with regard to views, I believe Oracle has a concept called Query re-write where it substitutes the select of the view in place which enables the result-set to be limited. For now I am going to use a temp table to only store the aggregates for invoices being reported on. – Jeremie May 30 '13 at 20:09

0 Answers0