sqlfirebirdlibreoffice-basefirebird-embedded

SUM() taking from only one row


Two tables: "S" (for "Services") and "Payments". They're tied together via the "S"."ID-S" being referenced as a foreign key: "Payments"."S".

I'm trying to create a query for a dropdown list in an "add payment" form, but since I hope to allow for partial payments, I want to substract the sum of the payments already made that are tied to the given "ID-S". However, I can't seem to hide the services paid off with multiple payments.

The following is my current code, using just one of the category of "services" (in this case the invoices):

SELECT "S"."Invoice" || ' for $' || "S"."Price" -
IIF("Payments"."S" IS NULL, 0, SUM("Payments"."Amount")
AS "To-Pay", "ID-S"
FROM "S"
LEFT OUTER JOIN "Payments" ON "S"."ID-S" = "Payments"."S"
GROUP BY "S"."Invoice", "S"."Price", "Payments"."Amount", "Payments"."S", "S"."ID-S"
HAVING "Payments"."S" IS NULL OR
SUM("Payments"."Amount") < "S"."Price"

It's supposed to show, for example:

etc, with the price being the remaining price to pay. It's not supposed to show completely paid off invoices at all.

As far as I can tell, the problem is that the SUM("Payments"."Amount") doesn't sum all the "Amount" columns with a matching "S-ID", it only takes the "Amount" from the given row. This doesn't help me one bit, because if, say, a $3000 invoice is paid off with two payments of $1000 and $2000 respectively, the list will not only still show the invoice, but show it twice - once with $2000 remaining and once with $1000 remaining.

I'm using LibreOffice Base with Firebird.

EDIT: Upon some further data input, I've found one case of double payment being displayed as mentioned above (two times with different "prices remaining"), yet another such double payment displays once with "$0" price, perhaps due to being split exactly half-in-half?


Solution

  • Perhaps you should extract/encapsulate grouping into a separate query. It is hard to reason without seeing example data, but try to do use either Derived Table or Common Table Expression.

    Below are just topmost google results to give you a general idea.

    Firebird-specific manual is at https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html

    Also - do you really need it all done on the server, like concatenating text strings? Usually it is made on-client with localization and font decorating and what not.

    Pattern to try:

    WITH Parts AS ( 
      SELECT ID_S, Sum(Amount) as Done 
      FROM Payments 
      GROUP BY 1
    ) 
    SELECT S.Invoice, S.Price - COALESCE( Parts.Done, 0)
    FROM Services S
    LEFT JOIN Parts ON S.ID = Parts.ID_S
    -- WHERE S.Price > COALESCE( Parts.Done, 0) 
    WHERE S.Price > Parts.Done OR Parts.Done IS NULL
    

    Or equal pattern

    SELECT S.Invoice, S.Price - COALESCE( Parts.Done, 0)
    FROM Services S
    LEFT JOIN ( SELECT ID_S, Sum(Amount) as Done FROM Payments GROUP BY 1) 
         AS Parts ON S.ID = Parts.ID_S
    -- WHERE S.Price > COALESCE( Parts.Done, 0) 
    WHERE S.Price > Parts.Done OR Parts.Done IS NULL