Mysql sum with group_concat and join tables - mysql

I've trying to solve this problem for about weeks now, but still have no answers
i want to show the total quantity of the inventory_table that has the same product barcode and show also its item description.
I have three tables
product_table
ID| barcode | brand | unit | price
1 | 1111111 | Neozep | Tablet | 5.50
2 | 2222222 | Biogesic | Syrup | 7.50
inventory_table
ID| batch | Total| barcode
1 | 5555555 | 100 | 1111111
2 | 6666666 | 500 | 1111111
productcontains_table
ID| Name | Amount | Type | barcode
1 | Paracetamol | 250 | mg | 1111111
2 | Amoxicilin | 20 | ml | 1111111
And the output should be like this
Barcode | Item Description | Price | Total Qty | Amount
1111111 | Paracetamol 250 mg | Amoxicilin 20 ml | P5.50 | 600 | P3300
My current Sql statement but this is obviously wrong hope you can help me guys
thanks in advance
SELECT
GROUP_CONCAT(DISTINCT productcontains_table.name ,' ',
productcontains_table.Amount,' ',
productcontains_table.Type
ORDER BY productcontains_table.IDno SEPARATOR ' | ' ) AS ItemDescription,
product_table.product_price AS Price,
SUM(inventory_table.inventory_total) AS TotalQuantity
product_table.price AS Price,
SUM(inventory_table.total) AS TotalQuantity,
product_table.price * SUM(inventory_table.total) AS TotalAmount
FROM inventory_table
JOIN product_table
ON product_table.barcode = inventory_table.barcode
JOIN productcontains_table
ON productcontains_table.barcode = product_table.barcode
GROUP BY inventory_table.barcode

Fixed a couple of typos:
SELECT inventory_table.barcode,
GROUP_CONCAT(DISTINCT productcontains_table.name,' ', productcontains_table.Amount,' ', productcontains_table.Type SEPARATOR ' | ') AS ItemDescription,
product_table.price AS Price,
SUM(inventory_table.total)/ b.cnt AS TotalQuantity,
product_table.price * SUM(inventory_table.total) / b.cnt AS Amount
FROM inventory_table
JOIN product_table ON product_table.barcode = inventory_table.barcode
JOIN productcontains_table ON productcontains_table.barcode = product_table.barcode
JOIN
( SELECT barcode,
count(productcontains_table.name) AS cnt
FROM productcontains_table )b ON b.barcode=product_table.barcode
GROUP BY inventory_table.barcode,
product_table.price,
inventory_table.barcode
http://sqlfiddle.com/#!9/2f372/37

Related

Joining 4 Tables together and checking where totals do not match

I have 4 tables act,up, pos_act, pos_up
In this example, let's say I have customer ID and Amount columns as
act.cust_id, up.cust_id, act.amount, up.amount
pos_up.cID, pos_act.cID, pos_up.amount_, pos_act.amount_
act
| cust_id | amount |
|:-------:|:------:|
| 6789 | 30.00 |
| 9876 | 25.00 |
pos_act
| cID | amount_|
|:-------:|:------:|
| 6789 | 30.00 |
| 9876 | 24.99 |
----------------------------------------
up
| cust_id | amount |
|:-------:|:------:|
| 1234 | 10.00 |
| 2345 | 75.00 |
pos_up
| cID | amount_|
|:-------:|:------:|
| 1234 | 9.99 |
| 2345 | 75.00 |
Now With this, I want to compare where amounts do not match all in one table.
So in this example 2345 matches in up but in act 1234 does not match.
Then the results should be
All Unmatched
| cust_id | Table |
|:-------:|:------:|
| 9876 | Act |
| 1234 | Up |
I tried with unions but cant seem to get that working
SELECT *
FROM (
select cID, amount FROM act as a
union select cID, amount FROM up as b
) as v
LEFT JOIN
(select CID, amount_ FROM pos_up as c
UNION select CID, amount_ from pos_act as d
) as r
WHERE a.amount != d.amount_
I also tried with left joins but it just shows me all results. I only want ones that do not match. custid is a unique ID and may appear multiple times.
You just use UNION in a wrong place
SELECT cID, amount, 'act' as `table`
FROM act as a
LEFT JOIN pos_act as pa
ON a.cust_id = pa.
WHERE a.amount != pa.amount_
UNION ALL
SELECT cID, amount, 'up'
FROM up as u
LEFT JOIN pos_up as pu
ON u.cust_id = pu.cID
WHERE u.amount != pu.amount_

Group Concat in mysql statement

I've got a table called delitems with some colums.
Within my SELECT statement I want to use a GROUP_CONCAT:
+-------------------------------+-------+--------+--------+-----+
| COLOR | tOTAL | Ptotal | Amount | qty |
+-------------------------------+-------+--------+--------+-----+
| BLUE - W = 55,BLUE - W/O = 93 | 148 | 375 | 55500 | 2 |
+-------------------------------+-------+--------+--------+-----+
mysql>select GROUP_CONCAT(color,' = ',qty) as COLOR, SUM(qTY) AS tOTAL, suM(p_cost) as Ptotal, SUM(qty)*SUM(p_cost) as Amount,count(*) qty from delitems where status='3' Group By cont_no;
Everything works fine except the Amount column. The total amount is wrong! Here the correct value:
+-----------------+-------+--------+--------+-----+
| COLOR | tOTAL | Ptotal | Amount | qty |
+-----------------+-------+--------+--------+-----+
| BLUE - W = 55 | 55 | 125 | 6875 | 1 |
| BLUE - W/O = 93 | 93 | 250 | 23250 | 1 |
+-----------------+-------+--------+--------+-----+
mysql>select GROUP_CONCAT(color,' = ',qty) as COLOR, SUM(qTY) AS tOTAL, suM(p_cost) as Ptotal, SUM(qty)*SUM(p_cost) as Amount,count(*) qty from delitems where status='3' Group By color;
I only want to display it in one line with the correct total amount
Please help.
Should be you need sum(a*b) not sum(a)*sum(b)
select
GROUP_CONCAT(color,' = ',qty) as COLOR
, SUM(qTY) AS tOTAL
, suM(p_cost) as Ptotal
, SUM(qty*(p_cost) as Amount, count(*) qty
from delitems
where status='3' Group By cont_no;

Select SUM from multiple tables for every record in MySQL table

I'm having a table with main invoice data, and two table with invoice items:
items which are based on hourly work, with an hourly rate and an amount of hours
items which are products, with a unit count an unit price
For the invoice overview page, I'd like to retrieve all invoices and their total amounts with one query.
A simplified schema
invoices_main
| invoice_id |
| 1 |
| 2 |
| 3 |
invoices_items_products
| item_id | invoice_id | item_count | item_unit_price |
| 1 | 1 | 1 | 999.95 |
| 2 | 1 | 20 | 49.50 |
| 3 | 2 | 3 | 15.00 |
| 4 | 2 | 5 | 5.00 |
| 5 | 3 | 2 | 150.00 |
invoices_items_hourly
| item_id | invoice_id | item_hours | item_hourly_rate |
| 1 | 1 | 3.50 | 90.00 |
| 2 | 1 | 1.00 | 140.00 |
| 3 | 2 | 12.00 | 90.00 |
| 4 | 3 | 1.50 | 90.00 |
With the help of this question, I've constructed the following query:
SELECT
I.invoice_id,
IFNULL(
SUM(ROUND(P.item_unit_price * P.item_count, 2)),
0
) + IFNULL(
SUM(ROUND(H.item_hourly_rate * H.item_hours, 2)),
0
) AS invoice_total_amount
FROM
invoices_main I
LEFT JOIN invoices_items_products P ON I.invoice_id = P.invoice_id
LEFT JOIN invoices_items_hours H ON I.invoice_id = H.invoice_id
GROUP BY
I.invoice_id
It works kind of, but if an invoice has both products and hourly items, with at least multiple entries for one of both, items are duplicated due to the joins and the total amount becomes way too high.
Thus, in the above example schema, it goes wrong with invoice_id 1 and 2, but work with 3.
How can I retrieve a list of invoices with their respective total amounts, in a way that works even if an invoice has multiple products and multiple hourly items?
Try putting both left join's into a subquery instead.
SELECT
I.invoice_id,
IFNULL
(
(
SELECT SUM(ROUND(H.item_hourly_rate * H.item_hours, 2))
FROM invoices_items_hours AS H
WHERE H.invoice_id = I.invoice_id
)
, 0
) +
IFNULL
(
(
SELECT SUM(ROUND(P.item_unit_price * P.item_count, 2))
FROM invoices_items_products AS P
WHERE P.invoice_id = I.invoice_id
)
, 0
) AS invoice_total_amount
FROM invoices_main AS I
GROUP BY I.invoice_id
As mentioned in the comments, you should sum up the revenue in each table per invoice_id before doing the join. If you're looking to get the revenue from both of these places then you can add (B.unit_revenue + C.hourly_revenue) total_revenue to the first SELECT statement below.
SELECT A.invoice_id, B.unit_revenue, C.hourly_revenue FROM
invoices_main AS A
JOIN (
SELECT invoice_id, SUM(item_count * item_unit_price) unit_revenue
FROM invoices_items_products GROUP BY invoice_id
) B
ON
A.invoice_id = B.invoice_id
JOIN (
SELECT invoice_id, SUM(item_hours * item_hourly_rate) hourly_revenue FROM
invoices_items_hours GROUP BY invoice_id
) C
ON
A.invoice_id = C.invoice_id

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

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