Home > OS >  SQL sum-function and count-function over several tables result in multiplied values
SQL sum-function and count-function over several tables result in multiplied values

Time:11-04

After driving myself crazy by countless attempts, I turn to you and hope someone is willing to help me....

I have 4 tables: SO (ServiceOrder), PR (PreRecording), IH (InvoiceHeader) and IL (InvoiceLine), with the columns and rows like underneath:

SO (ServiceOrder):

SO.No_
SO2101234
SO2101235
SO2101237
SO2101239

PR (PreRecording):

PR.No_ PR.Line PR.Amount
SO2101234 1 50
SO2101234 2 18
SO2101239 1 110
SO2101239 2 40
SO2101239 3 40

IH (InvoiceHeader):

IH.No_ IH.SO
VF2134889 SO2101234
VF2134890 SO2101235
VF2134891 SO2101239
VF2134892 SO2101234
VF2134893 SO2101239

IL (InvoiceLine):

IL.DocNo_ IL.LineNo IL.LineAmount
VF2134889 1 55
VF2134889 2 23
VF2134890 1 12
VF2134890 2 34
VF2134890 3 87
VF2134891 1 114
VF2134892 1 53
VF2134892 2 25
VF2134892 3 17
VF2134892 4 15
VF2134893 1 43
VF2134893 2 38

Relations:

  • PR.No_ = SO.No_
  • IH.SO = SO.No_
  • IL.DocNo_ = IH.No_

Desired outcome:

SO.No_ PR.SumAmount IH.SumAmount
SO2101234 68 188
SO2101235 0 133
SO2101237 0 0
SO2101239 190 195

With my usual simple inner/outer/joins I don't succeed, it's clear that some SELECT's should be nested. With a simple query to combine SO and PR, I have no problem. With a simple query to combine SO and IH, I have no problem. However, when I try to setup a query to get all of this in one output, it gets messed up and values start to multiply due to the rows that are used/found in the several tables.

Many thanks in advance....

CodePudding user response:

A simple strategy is to flatten the result before doing other lookups. I don't fully grasp what you need to return here but this is the general idea.

with SOPR as (
    /* first-level aggregated results */
    select SO.No_, sum(PR.Amount) as PRAmount
    from SO inner join PR on PR.No_ = SO.No_
    group by SO.No_
)
select
    SOPR.No_, min(SOPR.PRAmount) as PRAmount,
    sum(IL.Amount) as ILAmount
/* now look up next level of details */
from SOPR
    inner join IH on IH.SO = SOPR.No_
    inner join IL on IL.DocNo_ = IH.No_
group by SOPR.No_

CodePudding user response:

You can simply nest your queries so that you do the outer SELECT from a flat inner SELECT. This will also work if your RDBMS version does not support WITH CTEs.

To preserve the rows with NULL values, I used LEFT JOINS and additionally the COALESCE function to get 0 as result instead of NULL, as in your desired outcome.

   SELECT PRGRP.No_, 
          COALESCE(PRGRP.SumAmount, 0) AS PRAmount,
          COALESCE(SUM(IL.LineAmount), 0) AS ILAmount
     FROM (   SELECT SO.No_, SUM(PR.Amount) AS SumAmount
                FROM ServiceOrder SO 
           LEFT JOIN PreRecording PR 
                  ON PR.No_ = SO.No_
            GROUP BY SO.No_
          ) PRGRP
LEFT JOIN InvoiceHeader IH 
       ON IH.SO = PRGRP.No_
LEFT JOIN InvoiceLine IL 
       ON IL.DocNo_ = IH.No_
 GROUP BY PRGRP.No_

Result:

No_ PRAmount ILAmount
SO2101234 68 188
SO2101235 0 133
SO2101237 0 0
SO2101239 190 195

Full MySQL example in this db<>fiddle.

  •  Tags:  
  • sql
  • Related