Avoid duplicate values using join with multiple tables in Firebird - sql

I have 3 tables
Payments
PaymntID
Date
Amount
1
Ago.2021
500
2
Sep.2021
1200
3
Oct.2021
600
CashPayments
PaymntID
Amount
1
500
2
400
3
200
CreditCardPayments
PaymntID
Amount
CreditCard
2
450
Visa
2
350
MC
3
400
Visa
I need to get the PaymentID, date, amount payed in cash and amount payed in creditcard, but with the following query I'm getting duplicates.
Just a quick note, I can have two different credit cards used in one payment, but I can also have 2 different "cash payments" used in one payment.
Query:
select
PA.DATE AS PaymntDate,
PA.PaymntID AS PaymntID,
CP.amount AS CashAmount,
CCP.amount AS CreditAmount,
from Payments PA
LEFT join CashPayments CP on PA.PaymntID = CP.PaymntID
LEFT join CreditCardPayments CCP on PA.PaymntID = CCP.PaymntID
I'm getting the following result:
Result
PaymntID
PaymntDate
CashAmount
CreditAmount
1
Ago.2021
500
null
2
Sep.2021
400
450
2
Sep.2021
400
350
3
Oct.2021
200
400
So in this case, the cashpayment in paymntid 2 is duplicated. What I need is the following table:
Result
PaymntID
PaymntDate
CashAmount
CreditAmount
1
Ago.2021
500
null
2
Sep.2021
400
800
3
Oct.2021
200
400

You need to aggregate the values for each ID before joining. Probably the most succinct way is to use a CTE and then outer join each to your payments table, something like the following:
with cp as (
select paymentId, Sum(Amount) Amount
from CashPayments
group by PaymentId
), ccp as (
select paymentId, Sum(Amount) QAmount
from CreditCardPayments
group by PaymentId
)
select p.PaymentId, p.Date,
Coalesce(cp.Amount,0) CashAmount,
Coalesce(ccp.Amount,0) CreditAmount
from Payments p
left join cp on cp.PaymentId = p.PaymentId
left join ccp on ccp.PaymentId = p.PaymentId

Related

Sql code returns unexpected results. How to correct it

I'm using Firebird 3. There are 'sellers' master table for my contragent sellers, detailed 'Doc' table for goods income documents and subdetail table 'paym' for payments.
Seller: Seller_id, seller
Docs: doc_id, doc_summa, part_id
Paym: paid_id, doc_id, paid
Seller:
seller_id
seller
8
Firm1
45
Firm2
Docs:
doc_id
doc_summa
seller_id
346
1000
8
347
600
45
348
800
45
Paym:
paym_id
doc_id
paid
1
346
100
2
346
100
3
347
200
4
348
100
5
348
50
My aim is to get my residual debts(income-payment) like this:
seller_id
summa
paid
debt
8
1000
200
800
45
1400
350
1050
but get this multiplied, wrong summas:
seller_id
summa
paid
debt
8
2000
200
800
45
2200
350
1850
SELECT
s.seller_id,
sum(d.doc_summa) as summa,
sum(p.paid) as paid,
sum(d.doc_summa)-sum(p.paid) as debt
FROM seller s Left Join Docs d on s.seller_id=d.seller_id
Left Join paym p on p.doc_id= d.doc_id
GROUP BY s.seller_id
What is wrong in my SQL code?
The problem with your query is that because there are multiple payments for doc_ids 346 and 348, you will have two rows with a doc_summa of 1000 and 800 respectively, when you then sum them, the total becomes 2000 for seller_id 8 and 2200 for seller_id 45.
To solve this, you need to consolidate (sum) the payments before joining with docs. For example like the following:
with consolidated_paym as (
select
doc_id,
sum(paid) as total_paid
from paym
group by doc_id
)
select
s.seller_id,
sum(d.doc_summa) as summa,
sum(p.total_paid) as paid,
sum(d.doc_summa - p.total_paid) as debt
from seller s
left join docs d
on d.seller_id = s.seller_id
left join consolidated_paym as p
on p.doc_id = d.doc_id
group by s.seller_id
Fiddle: https://dbfiddle.uk/6_vyCu0w

How to apply join on tables while using having function?

There are two tables - trans and customer.
trans
customerid
pdate
purchase
1
11-01-2021
200
2
13-02-2021
400
1
18-01-2021
400
3
31-01-2021
600
4
23-03-2021
700
customer
customerid
firstname
lastname
1
raj
sharma
2
rahul
dev
3
riya
sen
4
rose
menon
The question is -
Find the firstname, lastname and sum of the purchase of the customers where sum of the purchase is greater than 500 in the month of January (Without using any CTE).
My take on this was -
SELECT
c.firstname,
c.lastname,
SUM( t.purchase )
FROM
customer c
INNER JOIN trans t ON c.id = t.id
GROUP BY
c.firstname,
c.lastname
HAVING
SUM( t.purchase ) > 500;
But this ignores the customers with id 1. The customerid 1 has made a purchase twice and the sum of his purchase is greater than 500.
I am using PostgreSQL.

Calculate total donations based on an attribute table

I am trying to get a list of donors who have cumulatively donated $5K+ between two different campaigns. My data is something like this
Attributes table
transactionid
attributevalue
123231
campaign 1
123456
campaing 2
123217
campaign 1
45623
campaing 2
65791
campaing 3
78931
campaign 4
11111
campaign 5
22222
campaing 6
Donations table
transactionid
donationamount
donorid
123231
2000
1233
123456
30000
1456
45623
8000
1233
78931
90
8521
11111
20
1233
22222
68
1456
Donor table
donorid
name
1233
John
1456
Mary
8521
Karl
This is what I tried, but the total I am getting is not right at all.
WITH test AS (
SELECT don.donorid,don.donationamount,a.attributevalue
FROM attributes table a
INNER JOIN donations don ON don.transactionid=a.transactionid
)
SELECT d.donorid,
SUM(CASE WHEN test.attributevalue='campaign 1' OR test.attributevalue='campaign 2'
THEN test.donationamount END) AS campaing_donation,
SUM(test.donationamount) AS total_donations
FROM donortable d
INNER JOIN test ON d.donorid = test.donorid
GROUP BY d.donorid
HAVING SUM(CASE WHEN test.attributevalue = 'campaign 1' OR test.attributevalue = 'campaign 2' THEN test.donationamount END) > 5000
but this is not working. My total donations sum is giving a value that is several times higher than the actual value.
Ideally, the final result would be something like this:
donorid
campaign_amount
totalamount
1233
10000
10020
1456
30000
30068
Select
sum (Donations.donationamount),
donor.donorid,
donor.name
from
Attributes
join Donations on
Donations.transactionid = attributes.transactionid
Join Donor on
donor.donorid = donations.donorid
Where
Attribute.attributevalue in ('campaign 1','campaign 2')
Group by
donor.donorid,
donor.name
create table #transection_tbl(tran_id int,attributevalue varchar(20))
create table #donation_tbl(tran_id int,donation_amount int ,donar_id int)
select donar_id,max(donation_amount) as 'campaing_amount',
sum(donation_amount) as 'totalamount'
from #transection_tbl as t1
inner join #donation_tbl as t2 on t1.tran_id=t2.tran_id
group by donar_id
having COUNT(attributevalue)=2

Get the product with highest sales

I need a query to return the products that have been sold most often.
I have two tables to work with.
Product
IDPRO(PK) DESCRIP STOCK PRICE
4000 PIZZA 7 2000
4001 HAMBURGUESA 8 800
4002 PAELLA 1 1000
4003 CORDERO 5 3000
4004 COMIDA CHINA 9 500
4005 ALBONDIGAS 9 500
Details
IDPRO(FK) Amount
4002 2
4003 1
4004 1
4002 3
4002 1
4003 100
4004 50
4004 3
4005 10
The result would be something like this
CORDERO
Since it is the product with the highest amount of sold units.
If you need the total quantity you could use sum and group by on the joined tables
select t1.IDPRO, t1.DESCRIP, sum(t2.Amount) total
FROM Product t1
INNER JOIN DETAILS t2 on t2.IDART = t1.IDPRO
GROUP BY t1.IDPRO, t1.DESCRIP
ORDER BY total desc
First find the sum of CANTIDAD column for each product and select top 1 row and join to table 1.
Query
select top 1 t1.IDPRO, t1.DESCRIP, t2.total
from Product t1
join (
select IDART, sum(Amount) as total
from Details
group by IDART
)t2
on t1.IDPRO = t2.IDART
order by t2.total desc;
Try somethink like this for top 1:
WITH MAIN AS(
SELECT main.IDPRO, main.DESCRIP, main.CANTIDAD from Details det
LEFT JOIN Product main ON main.IDPRO=det.IDART)
SELECT TOP 1 * from MAIN

Full Join and sum 2 queries in access

I am very new to this type of complicated joins and summing functions.
I had 2 table queries which have same fields (i.e: ProdID, ProdName, NetQty, Unit)
The 1st one query contains OpStock and the 2nd one contains Purchase.
I want to add this 2 table query to make a single table so that I can able to see current stock.
The data looks like this for 1 st table is:
ProdID ProdName Qty
100 Rose 700
101 Lilly 550
103 Jasmine 600
105 Lavender 400
The data looks like this for 2nd table is:
ProdID ProdName Qty
100 Rose 400
101 Lilly 250
104 Lotus 1000
106 MariGold 400
The final data looks like this for 3rd table is:
ProdID ProdName Qty
100 Rose 1100
101 Lilly 800
103 Jasmine 600
104 Lotus 1000
105 Lavender 400
106 MariGold 400
How can i achieve this one using sql for access2003.
Thanks.
I am very sorry Ciaran,
This is purely access used for vb.net
Here Is my access query1
SELECT sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
Sum(([sp_OpenIandP_Prod.SumOfNetQty]-[sp_OpenSales_Prod.SumOfNetQty])) AS NetQty,
sp_OpenIandP_Prod.UnitSName
FROM sp_OpenIandP_Prod
INNER JOIN sp_OpenSales_Prod ON sp_OpenIandP_Prod.ProdID=sp_OpenSales_Prod.ProdID
GROUP BY sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
sp_OpenIandP_Prod.UnitSName;
The 1st query result would be like this:
ProdID ProdName NetQty UnitSName
1 Rose 0 Kgs
2 Lilly 7125 Mts
3 Lotus 12374 Nos
The second query is:
SELECT Products.ProdID, Products.ProdName,
Sum(OPDDetails.NetQty) AS SumOfNetQty, Units.UnitSName
FROM Units
INNER JOIN (Products
INNER JOIN (Brands
INNER JOIN OPDDetails ON Brands.BrID=OPDDetails.BrandID)
ON Products.ProdID=Brands.ProdID)
ON Units.UnitID=Products.UnitID
WHERE (((OPDDetails.PurID)>0)
AND ((OPDDetails.OPDDate)>=[StartDate] And (OPDDetails.OPDDate)<=[EndDate]))
GROUP BY Products.ProdID, Products.ProdName, Units.UnitSName;
and the result set would be like this:
ProdID ProdName SumOfNetQty UnitSName
1 Rose 1800 Kgs
2 Lilly 21000 Mts
I got the above result easily.
But it is not as much easy to get like this:
ProdID ProdName SumOfNetQty UnitSName
1 Rose 1800 Kgs
2 Lilly 28125 Mts
3 Lotus 12374 Nos
That's all. Thanks again.
This is not a vb.net question, however you need to use a UNION
Select ProdId, ProdName, Sum(Qty) As QtySum
From (Select ProdId, ProdName, Qty From TableA
Union All
Select ProdId, ProdName, Qty From TableB) DerrivedView
Group By ProdId, ProdName
You can create a UNION between your 2 queries then group by product:
SELECT ProdID, ProdName, Sum(NetQty) As NetQty, UnitSName
FROM
(
SELECT sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
Sum(([sp_OpenIandP_Prod.SumOfNetQty]-[sp_OpenSales_Prod.SumOfNetQty])) AS NetQty,
sp_OpenIandP_Prod.UnitSName
FROM sp_OpenIandP_Prod
INNER JOIN sp_OpenSales_Prod ON sp_OpenIandP_Prod.ProdID=sp_OpenSales_Prod.ProdID
GROUP BY sp_OpenIandP_Prod.ProdID,
sp_OpenIandP_Prod.ProdName,
sp_OpenIandP_Prod.UnitSName
UNION ALL
SELECT Products.ProdID, Products.ProdName,
Sum(OPDDetails.NetQty) AS NetQty, Units.UnitSName
FROM Units
INNER JOIN (Products
INNER JOIN (Brands
INNER JOIN OPDDetails ON Brands.BrID=OPDDetails.BrandID)
ON Products.ProdID=Brands.ProdID)
ON Units.UnitID=Products.UnitID
WHERE (((OPDDetails.PurID)>0)
AND ((OPDDetails.OPDDate)>=[StartDate] And (OPDDetails.OPDDate)<=[EndDate]))
GROUP BY Products.ProdID, Products.ProdName, Units.UnitSName
)
GROUP BY ProdID, ProdName, UnitSName