MySQL: Join 3 tables with distinct values - mysql

So I have 3 tables: tableA, tableB, tableC with structures as follows
tableA
id
name
state
1
Ray
MD
2
Sam
LA
3
John
NY
tableB
id
a_id
amount
code
1
2
10
CHARGE
2
2
20
CHARGE
3
3
70
CHARGE
tableC
id
a_id
amount
code
1
2
50
CHARGE
2
2
40
DEPOSIT
3
1
60
CHARGE
I need the output of the join as follows:
A id
amount
1
60
2
30
3
70
So, here it calculates the sum of amount based on id in tableA. It checks the tableB for amount and if not present only then it checks tableC. Thats why the id 2 has amount 30 in output.
But what actually happens is the sum of both tables are added. So I get amount 120 for id 2. How do I get the required output?
So I tried this query here
Select if( SUM(CASE WHEN B.code != 'DEPOSIT'
THEN B.amount
ELSE 0 END) > 0,
SUM(CASE WHEN B.code != 'DEPOSIT'
THEN B.amount
ELSE 0 END),
SUM(CASE WHEN C.code != 'DEPOSIT'
THEN C.amount
ELSE 0 END)) as total
FROM tableA as A
left join tableB AS B on A.id=B.a_id
LEFT JOIN tableC AS C on A.id=C.a_id
GROUP BY A.id

You can try a solution like this
Select A.id, SUM(if(B.amount is NOT NULL,B.amount, C.amount)) as total
FROM tableA as A
LEFT JOIN tableB AS B on A.id=B.a_id and B.code != 'DEPOSIT'
LEFT JOIN tableC AS C on A.id=C.a_id and C.code != 'DEPOSIT'
GROUP BY A.id

Test this:
SELECT id, CASE WHEN b.amount
THEN b.amount
ELSE c.amount
END amount
FROM tableA a
LEFT JOIN ( SELECT a_id id,
SUM( CASE WHEN code != 'DEPOSIT'
THEN amount
ELSE 0
END ) amount
FROM tableB
GROUP BY id ) b USING (id)
LEFT JOIN ( SELECT a_id id,
SUM( CASE WHEN code != 'DEPOSIT'
THEN amount
ELSE 0
END ) amount
FROM tableC
GROUP BY id ) c USING (id)

Related

Have any MySQL query to Update/replace Group By table points into other MySQL Table

I Filter the My (TableA - fields app_id, user_id, points, tr_type, description) using Below Query
select app_id, user_id,sum(case when tr_type = 'add' then points when tr_type = 'sub' then - points end) as points
from TableA
group by app_id, user_id;
In Resuts:
app_id user_id points
1 1a 10
1 1b 12
1 1c 3
Now I have another table (TableB)
app_id user_id points desc
1 1a 0 text
1 1b 0 tet
1 1c 0 txt
now I need fast replacement query to update TableB point values which is groupby from TableA
You can use a inner join with subqiery for group by values
update tableB b
INNER JOIN (
select app_id
, user_id
,sum(case when tr_type = 'add' then points when tr_type = 'sub' then - points end) as points
from TableA
group by app_id, user_id
) t ON t.app_id = b.app_id
AND t.user_id = b.user_id
set b.points = t.points

MYSQL Query for the below

I have join query which is not returning the result as expected. Below is the table structure, query used, result and expected result
Table A:
Id Name Token
1 A abcdef
2 B think
3. C Bxjscmsdnj
Table B:
id TableA_id configKey configValue
1 2 pmt ins
2 2 vat gas
3 1 vat nnnb
4 1 pmt mc
5 3 vat nhu
6 3 pmt nnu
7 2 hit bxhsjab
Below is the query that I used:
SELECT A.Token,
A.Name,
CASE
WHEN B.configKey = 'pmt’ THEN B.configValue
ELSE ''
END AS ‘PMT’,
CASE
WHEN B.configKey = ‘vat’ THEN B.configValue
ELSE ''
END AS ‘VAT’
FROM TABLEA A
INNER JOIN TABLEB B ON A.Id = B.TableA_id
WHERE B.configKey IN (‘PMT’, ‘VAT’)
ORDER BY A.id DESC;
Result:
Token Name PMT VAT
1 A nnnb
1 A mc
2 B gas
2 B ins
Expected Result:
Token Name PMT VAT
1 A mc nnnb
2 B ins gas
You want conditional aggregation. First, add a group by clause that groups together rows having the same id and name; then, wrap the case expressions in an aggregate function such as max():
select
a.id,
a.name,
max(case when b.configkey = 'pmt' then b.configvalue end) pmt,
max(case when b.configkey = 'vat' then b.configvalue end) vat
from tablea a
inner join tableb b on a.id = b.tablea_id
where b.configkey in ('pmt', 'vat')
group by a.id, a.name
order by a.id desc;

Getting data form 2 tables and summing values of the result

I have 2 tables with information: ID, persona_id, total_amount
The persona ID can repeat dozen of times. So i get all the one persons id total_amount with query:
select d.id as debt_id, p.name as persona, sum(d.total_amount) as total_amount
from debt d
join persons p on d.persona_id = p.id group by p.name
I want to get data from each table in one query and do aritmethic propertys with the total_amount column and return it as 1 tabel.
TABLE 1
id persons_id total_amount
1 2 50
2 3 100
3 2 200
4 5 300
5 1 500
TABLE 2
id persons_id total_amount
1 2 25
2 1 100
3 5 50
4 3 100
5 4 300
As a result i want to get the 2 tables comined with arithmetic operation (-, +, / , * ) of Total amount columns.Basicaly a change to get the ending result total amount in form i want for different cases.
What worked for me based on JohnHC answear was :
select c.id, c.persona_id, c.total_amount - d.total_amount as new_total
from ( select c.id , c.persona_id, sum(c.total_amount) as total_amount from credit c
join persons p on c.persona_id = p.id
group by p.name) c
inner join ( select d.id, d.persona_id, sum(d.total_amount) as total_amount from debt d
join persons p on d.persona_id = p.id
group by p.name) d
on c.persona_id = d.persona_id
group by c.id, c.persona_id
If you want the total, try:
select id, person_id, sum(total_amount)
from
(
select id, person_id, total_amount
from table1
union all
select id, person_id, total_amount
from table2
)
group by id, person_id
If you want to do other things, try:
select t1.id, t1.person_id, t1.total_amount [+ - / *] t2.total_amount as new_total
from table1 t1
inner join table2 t2
on t1.id = t2.person_id
group by t1.id, t1.person_id

Join tables and update column on multiple conditions

I have two tables customers and orders, where important columns are:
/* Customers: */
id | login | membershipid
100 | email1 | 0
101 | email2 | 0
/* Orders: */
userid | total
100 | 150
101 | 120
101 | 450
I want to update membershipid depending of total purchases for each customer. Lets say it will be zero if the sum is less than 500, one if sum is 500-1000, two if sum is over 1000.
I get the sum this way:
SELECT customers.login, sum( orders.total ) AS total_purchased
FROM xcart_customers AS customers
LEFT JOIN xcart_orders AS orders ON customers.id = orders.userid
GROUP BY customers.login
but I am not sure how to update back customers table. Something like:
UPDATE xcart_customers set (membershipid) = (
SELECT sum( orders.total ) AS total_purchased
FROM xcart_customers AS customers
LEFT JOIN xcart_orders AS orders ON customers.id = orders.userid
GROUP BY customers.login
)
but where and how to use conditions (and will GROUP BY work?):
CASE
WHEN
..
ELSE
END
UPDATE xcart_customers
join
(
SELECT customers.login, sum( orders.total ) AS total_purchased
FROM xcart_customers AS customers
LEFT JOIN xcart_orders AS orders ON customers.id = orders.userid
GROUP BY customers.login
) tmp on tmp.login = xcart_customers.login
set xcart_customers.membershipid = case when total_purchased is null or total_purchased < 500 then 0
when total_purchased between 500 and 1000 then 1
else 2
end
One way to do this is with a join operation. Take your query, and turn it into an inline view, and join that back to the customers table.
We might want to handle the case when total_purchased is NULL as being less than 500 (when a customer doesn't have any related rows in xcart_orders.)
As a SELECT it would look like this:
SELECT t.login
, t.membershipid
, CASE
WHEN IFNULL(s.total_purchased,0) < 500 THEN 0
WHEN s.total_purchased <= 1000 THEN 1
WHEN s.total_purchased > 1000 THEN 2
ELSE NULL
END AS new_membershipid
FROM customers t
JOIN ( SELECT c.login
, SUM(o.total) AS total_purchased
FROM xcart_customers c
LEFT
JOIN xcart_orders o
ON o.userid = c.id
GROUP BY c.login
) s
ON s.login = t.login
To convert that into an UPDATE, replace the SELECT ... FROM with UPDATE
and add a SET clause at the end of the statement (before the WHERE clause if there was a WHERE clause).
For example:
UPDATE customers t
JOIN ( SELECT c.login
, SUM(o.total) AS total_purchased
FROM xcart_customers c
LEFT
JOIN xcart_orders o
ON o.userid = c.id
GROUP BY c.login
) s
ON s.login = t.login
SET t.membershipid =
CASE
WHEN IFNULL(s.total_purchased,0) < 500 THEN 0
WHEN s.total_purchased <= 1000 THEN 1
WHEN s.total_purchased > 1000 THEN 2
ELSE NULL
END
NOTE: This assumes that login is UNIQUE` in the customers table.
FOLLOWUP
Given that membershipid cannot be assigned a NULL value, we can tweak the CASE expression. Do the check for > 1000 first, then a check for >= 500, else 0.
For example:
CASE
WHEN s.total_purchased > 1000 THEN 2
WHEN s.total_purchased >= 500 THEN 1
ELSE 0
END

How to do I group or join a query together to get the list of items I need

I have a couple of tables:
Invoice
-----------------
ID total
1 500.00
2 100.00
3 10.00
Payment
---------------------------------------
ID invoiceId Amount Method
1 1 400 CASH
2 2 60 CASH
3 2 40 CREDIT
I need a query that gets all invoices where at least one payment.method is CREDIT and the sum of all payments for that invoice is greater than the total of the invoice.
And I need it to be fast.
How can I do this?
SELECT a.ID InvoiceID,
a.Total TotalInvoice,
b.TotalPayment
FROM Invoice a
INNER JOIN
(
SELECT InvoiceID, SUM(Amount) TotalPayment
FROM Payment
GROUP BY InvoiceID
HAVING SUM(Method = 'CREDIT') > 0
) b ON a.ID = b.InvoiceID AND
a.Total < b.TotalPayment
SQLFiddle Demo
Another method:
SELECT
i.`id`,
i.`total` AS `total_invoiced`,
SUM(p.`amount`) AS `total_payments`,
SUM(IF(p.`method`='credit', 1, 0)) AS `count_credit`
FROM `invoices` i
LEFT JOIN `payments` p ON (p.`invoice_id`=i.`id`)
WHERE 1=1
GROUP BY i.`id`
HAVING (`total_payments` > i.`total`) AND (`count_credit` > 0)
I changed some table/field names. Sorry for the inconvenience.
http://www.sqlfiddle.com/#!2/7402d/1/0
try this one:
select iagg.ID
from (
select i.ID
, sum (p.amount) tl_paid
, min (i.total) tl
from invoice i
join payment p on ( p.invoiceID = i.ID )
group by i.ID
) iagg
where exists (
select 1
from payment p2
where p2.invoiceId = iagg.ID
and p2.method = 'CREDIT'
)
and iagg.tl_paid > iagg.tl
;
the minimum operator over the total attribute is mandated by the grouping operator, the minimum is actually taken from a set of identical values.