Selecting related rows in MySQL - mysql

Let me elaborate. I have a table like this (updated to include more example)
| id | date | cust | label | paid | due |
+----+-----------+------+-------------------------+------+-------+
| 1 |2016-02-02 | 1 | SALE: Acme Golf Balls | 0 | 1000 |
| 20 |2016-03-01 | 1 | PAYMENT: transaction #1 | 700 | 0 |
| 29 |2016-03-02 | 1 | PAYMENT: transaction #1 | 300 | 0 |
| 30 |2016-03-02 | 3 | SALE: Acme Large Anvil | 500 | 700 |
| 32 |2016-03-02 | 3 | PAYMENT: transaction #30| 100 | 0 |
| 33 |2016-03-03 | 2 | SALE: Acme Rockets | 0 | 2000 |
Now I need to output a table that displays sales that haven't been paid in full and the remaining amount. How do I do that? There's not much info out there on how to relate rows from the same table.
EDIT: Here's the output table I'm thinking of making
Table: debts_n_loans
| cust | label | amount |
==========================================
| 3 | SALE: Acme Large Anvil | 100 |
| 2 | SALE: Acme Rockets | 2000 |

If cust is the key that ties them together, then you can just use aggregation and a having clause:
select cust, sum(paid), sum(due)
from t
group by cust
having sum(paid) <> sum(due);
If you want the details, you can use a join, in or exists to get the details.
EDIT:
If you need to do this using the transaction at the end of the string:
select t.id, t.due, sum(tpay.paid) as paid
from t left join
t tpay
on tpay.label like '%#' || t.id
where t.label like 'SALE:%' and
tpay.label like 'PAYMENT:%'
group by t.id, t.due
having t.due <> sum(tpay.paid);

So you only need the rows with a due greater than 0
SELECT * FROM <table> WHERE due > 0;

Try this:
SELECT
cust,
SUM(due) - SUM(paid) AS remaining
FROM t1
GROUP BY cust
HAVING SUM(due) > SUM(paid);

Related

Merge two tables with same structure and numers sum

Hello i have two tables with same structure and now I want merge it.
Here is structure:
Terms:
steamid - that goes without saying
regcas - keep only a smaller value
VIP - sum
FunVIP - ignore when duplicate
Days - sum
KilledCT - sum
WinPP - sum
LastT - sum
cas - sum
lastnick - ignore when duplicate
lastlog - ignore when duplicate
ct_cas - sum
simon_cas - sum
Example when duplicate:
row from main table
steamid | regcas | VIP | FunVIP | Days | KilledCT | WinPP | LastT | lastnick | lastlog | ct_cas | simon_cas
------------------------------------------------------------------------------------------------------------------------------
76561198040874389 | 1546639030 | 1 | 0 | 125 | 1000 | 20 | 50 | Bomber | 1546639037 | 64 | 50
row from second table
steamid | regcas | VIP | FunVIP | Days | KilledCT | WinPP | LastT | lastnick | lastlog | ct_cas | simon_cas
------------------------------------------------------------------------------------------------------------------------------
76561198040874389 | 1553888234 | 1 | 5 | 100 | 1555 | 40 | 20 | Lucker | 1549387793 | 10 | 1
Result
steamid | regcas | VIP | FunVIP | Days | KilledCT | WinPP | LastT | lastnick | lastlog | ct_cas | simon_cas
------------------------------------------------------------------------------------------------------------------------------
76561198040874389 | 1546639030 | 2 | 0 | 225 | 2555 | 60 | 70 | Bomber | 1546639037 | 74 | 51
I absolutely don't know how to compose a complex SQL statement and I need help.
You seem to want union all and group by. I have no idea what "ignore with duplicate" is supposed to mean, but min() seems close enough. So:
select steamid, min(regcas) as regcas, sum(vip) as vip),
min(FunVIP) as FunVIP,
sum(Days) as days, sum(KilledCT) as KilledCT, sum(WinPP) as WinPP,
sum(LastT) as LastT, sum(cas) as cas,
min(lastnick) as lastnick,
min(lastlog) as lastlog,
sum(ct_cas) as ct_cas, sum(simon_cas) as simon_cas
from ((select t1.* from table1 t1) union all
(select t2.* from table2 t2)
) t2
group by steamid;
To merge two tables.Can use join tables command.
select*from natural join ;
OR [1]
select*from, where column.table1=column.table2;

MYSQL join query not working as expected

I have basically have two tables:
1) billingcharges : here we store id of a restaurant (restid) , charge id (chargeid), chargetime(timeinmillis when the charge occurred),chargeamount(int amount of the actual charge).charge id is a foreign key to the billingchargedetails table.
2) billingchargedetails: here we store the details of all the possible charges. chargeid(primary key int), chargename (name of the charge), perdaycost (cost per day of the charge)
What i expect:
a summary report of totalamount of charge for each charge for each restaurant.
The current entries inside the tables are:
select * from billingcharges;
+--------+----------+---------------+--------------+
| restid | chargeid | chargetime | chargeamount |
+--------+----------+---------------+--------------+
| 1 | 1 | 1536363636363 | 700 |
| 2 | 1 | 1536363636363 | 500 |
| 1 | 1 | 1568789654123 | 500 |
+--------+----------+---------------+--------------+
select * from billingchargedetails;
+----------+--------------------+------------------+
| chargeid | chargename | chargecostperday |
+----------+--------------------+------------------+
| 1 | Base Charge | 50 |
| 2 | Spotlight Listing | 50 |
| 3 | Gold Notification | 500 |
| 4 | Discount (FIRST50) | 18 |
+----------+--------------------+------------------+
A simple join on chargeid ended up not giving me the qty and sum as expected.so i need some form of a left or right outer join, that much i know and tried
I tried a left join as follows:
select restid, B.chargeid, chargename, count(B.chargeid) as qty,
sum(ifnull(chargeamount,0)) as total
from billingcharges as B
left join billingchargedetails as C on B.chargeid=C.chargeid
group by restid,B.chargeid;
+--------+----------+-------------+-----+-------+
| restid | chargeid | chargename | qty | total |
+--------+----------+-------------+-----+-------+
| 1 | 1 | Base Charge | 2 | 1200 |
| 2 | 1 | Base Charge | 1 | 500 |
+--------+----------+-------------+-----+-------+
This does work and sums things but there are missing charges for each restaurant. even if they arent present inside the billinghcarges ie the left table, i need it with qty 0 and total 0.
I tried a right join and a random value was selected by mysql from the non existing entries inside the left table as follows:
select restid, B.chargeid, chargename, count(B.chargeid) as qty,
sum(ifnull(chargeamount,0)) as total
from billingcharges as B
right join billingchargedetails as C on B.chargeid=C.chargeid
group by restid,B.chargeid;
+--------+----------+-------------------+-----+-------+
| restid | chargeid | chargename | qty | total |
+--------+----------+-------------------+-----+-------+
| NULL | NULL | Spotlight Listing | 0 | 0 |
| 1 | 1 | Base Charge | 2 | 1200 |
| 2 | 1 | Base Charge | 1 | 500 |
+--------+----------+-------------------+-----+-------+
The expected output is something like:
restid chargeid chargename qty totalamount
1 1 Base Charge 2 1200
1 2 Spotlight 0 0
1 3 Gold 0 0
1 4 Discount 0 0
2 1 Base Charge 1 500
2 2 Spotlight 0 0
2 3 Gold 0 0
2 4 Discount 0 0
'same as above expected for each restid in billingcharges'
Before you can do the outer join, you need to generate the cross-product of restaurants to charge types.
Something like the following (but I have not tested it):
SELECT R.restid, D.chargename, COUNT(B.chargeid) AS qty,
SUM(IFNULL(B.chargeamount, 0)) AS total
FROM (SELECT DISTINCT restid FROM billingcharges) AS R
CROSS JOIN billingchargedetails AS D
LEFT JOIN billingcharges AS B ON R.restid=B.restid AND D.chargeid=B.chargeid
GROUP BY R.restid, D.chargename;
In this example, the cross-product of R and D is every restaurant crossed with every charge type.
Of course not all of those charges exist for every restaurant. So the outer join to billingcharges finds those rows that do exist for each respective combination of restaurant & charge type.

Mind numbing SQL madness

This query runs on an invoices table to help me decide who I need to pay
Here's the base table:
The users table
+---------+--------+
| user_id | name |
+---------+--------+
| 1 | Peter |
| 2 | Lois |
| 3 | Stewie |
+---------+--------+
The invoices table:
+------------+---------+----------+--------+---------------+---------+
| invoice_id | user_id | currency | amount | description | is_paid |
+------------+---------+----------+--------+---------------+---------+
| 1 | 1 | usd | 140 | Cow hoof | 0 |
| 2 | 1 | usd | 45 | Cow tail | 0 |
| 3 | 1 | gbp | 1 | Cow nostril | 0 |
| 4 | 2 | gbp | 1500 | Cow nose hair | 0 |
| 5 | 2 | cad | 1 | eyelash | 1 |
+------------+---------+----------+--------+---------------+---------+
I want a resulting table that looks like this:
+---------+-------+----------+-------------+
| user_id | name | currency | SUM(amount) |
+---------+-------+----------+-------------+
| 1 | Peter | usd | 185 |
| 2 | Lois | gbp | 1500 |
+---------+-------+----------+-------------+
The conditions are:
Only consider invoices that have not been paid, so where is_paid = 0
Group them by user_id, by currency
If the SUM(amount) < $100 for the user_id, currency pair then don't bother showing the result, since we don't pay invoices that are less than $100 (or equivalent, based on a fixed exchange rate).
Here's what I've got so far (not working -- which I guess is because I'm filtering by a GROUP'ed parameter):
SELECT
users.user_id, users.name,
invoices.currency, SUM(invoices.amount)
FROM
mydb.users,
mydb.invoices
WHERE
users.user_id = invoices.user_id AND
invoices.is_paid != true AND
SUM(invoices.amount) >=
CASE
WHEN invoices.currency = 'usd' THEN 100
WHEN invoices.currency = 'gbp' THEN 155
WHEN invoices.currency = 'cad' THEN 117
END
GROUP BY
invoices.currency, users.user_id
ORDER BY
users.name, invoices.currency;
Help?
You can't use SUM in a WHERE. Use HAVING instead.
Use HAVING clause instead of SUM in WHERE condition
Try this:
SELECT u.user_id, u.name, i.currency, SUM(i.amount) invoiceAmount
FROM mydb.users u
INNER JOIN mydb.invoices i ON u.user_id = i.user_id
WHERE i.is_paid = 0
GROUP BY u.user_id, i.currency
HAVING SUM(i.amount) >= (CASE i.currency WHEN 'usd' THEN 100 WHEN 'gbp' THEN 155 WHEN 'cad' THEN 117 END)
ORDER BY u.name, i.currency;
Try something like this:
SELECT
user_id, name, currency, sum(amount) due
FROM
invoice i
JOIN users u ON i.user_id=u.user_id
WHERE
is_paid = 0 AND
GROUP BY user_id, currency
having due >= 100
do you store exchange rates? Multiply rates with amount to get actual amount with respect to base currency.
sum(amount*ex_rate) due

MySQL using JOIN and reports

So, I've got a mysql query that looks like this:
SELECT rewards.name, redemptions.points, redemptions.value
FROM rewards
INNER JOIN redemptions ON rewards.id = redemptions.reward_id;
The problem is that it spits out a table like this:
-----------------------------
| Reward 1 | 500 | 30 |
-----------------------------
| Reward 1 | 500 | 30 |
-----------------------------
| Reward 1 | 500 | 30 |
-----------------------------
| Reward 2 | 100 | 10 |
-----------------------------
| Reward 2 | 100 | 10 |
-----------------------------
| Reward 3 | 250 | 20 |
-----------------------------
and so on. Ideally, what I would actually like it to do is to only list each one once, but sum certain columns. So for example, it would look something like this:
-----------------------------
| Reward 1 | 500 | 90 |
-----------------------------
| Reward 2 | 100 | 20 |
-----------------------------
| Reward 3 | 250 | 20 |
-----------------------------
Where it is summing the third column, but listing the first two columns just once. I thought maybe a union would do it because I know it ignores duplicates, but I don't think it works while using unions as well.
Use SUM, and remember to add GROUP BY:
SELECT rewards.name, redemptions.points, SUM(redemptions.value)
FROM rewards
INNER JOIN redemptions ON rewards.id = redemptions.reward_id
GROUP BY rewards.name;
SELECT a.name, b.points, SUM(b.value)
FROM rewards a
INNER JOIN redemptions b
ON a.id = b.reward_id
GROUP BY a.name, b.points

How to write queries to calculate today's due amount?

I have scheduled payments, so I have these tables:
customer
+id
paymentSchedule
+id
+customer_id
+amount //total price
+dueDate //date to be paid
payments
+id
+date
+customer_id
+paymentSchedule_id
+amount //amount paid, it can be a partial payment
How do I write a query to get Today's due amount by customer.
I mean I need to join the tables (thats my main problem) and then substract the
sum of the payments.mount minus the sum of the scheduledPaymens.amount
but.. how?
Thanks in advance
This is probably not 100%, but should be pretty solid to help you tweak:
SELECT customer_id, (due.amount - paid.amount) as amountDue
FROM
(SELECT customer_id, SUM(amount) as amount
FROM paymentSchedule
WHERE dateDate <= getDate()
and customer_id = #custid) as due
LEFT JOIN
(SELECT customer_id, SUM(amount) as amount
FROM payments
WHERE customer_id = #custid) as paid ON paid.customer_id = due.customer_id
Ok, this is how I understood the problem. I simplified the tables because they where just complicating things, and adding dates is just straight forward.
PaymentSchedule
+----+-------------+-----------------+
| id | customer_id | original_amount |
+----+-------------+-----------------+
| 1 | Tom | 100 |
| 2 | Tom | 200 |
| 3 | Tom | 300 |
| 4 | Moe | 400 |
+----+-------------+-----------------+
Payments
+----+--------------------+-------------+
| id | paymentSchedule_id | paid_amount |
+----+--------------------+-------------+
| 1 | 1 | 70 |
| 2 | 2 | 150 |
| 3 | 2 | 50 |
| 4 | 4 | 300 |
| 5 | 4 | 25 |
+----+--------------------+-------------+
Result of query
+-------------+-------------------+-----------------+-----------+----------------+
| CUSTOMER_ID | PAYMENTSCHEDULEID | ORIGINAL_AMOUNT | TOTALPAID | PENDINGPAYMENT |
+-------------+-------------------+-----------------+-----------+----------------+
| Tom | 1 | 100 | 70 | 30 |
| Tom | 2 | 200 | 200 | 0 |
| Tom | 3 | 300 | 0 | 300 |
| Moe | 4 | 400 | 325 | 75 |
+-------------+-------------------+-----------------+-----------+----------------+
Query with double select
select *, s.original_amount - s.TotalPaid as PendingPayment from (
select
ps.customer_id, ps.id as PaymentScheduleId, ps.original_amount,
coalesce(sum(p.paid_amount), 0) as TotalPaid
from paymentSchedule ps
left join payments p on p.paymentSchedule_id = ps.id
group by ps.customer_id, PaymentScheduleId, ps.original_amount
) as S
Query with single select
select
ps.customer_id, ps.id as PaymentScheduleId, ps.original_amount,
coalesce(sum(p.paid_amount), 0) as TotalPaid,
ps.original_amount - coalesce(sum(p.paid_amount), 0) as PendingPayment
from paymentSchedule ps
left join payments p on p.paymentSchedule_id = ps.id
group by ps.customer_id, PaymentScheduleId, ps.original_amount
The result of both queries is the same. I just wonder which one runs faster. You can try both and tell us :)
Let me know if this this is the result you expected
Something like this should be a good starting point for you to tweak.
SELECT c.*
FROM customer c
INNER JOIN paymentSchedule ps
ON c.id = ps.customer_id
LEFT JOIN payments p
ON ps.id = p.paymentSchedule_id
WHERE ps.dueDate = 'This depends on how you store dueDate'
AND ps.amount - p.amount > 0