How can I fix my table to make a expiration of medicine? - mysql

I'm doing an inventory system of drug store. And now I'm trying to do the expiration of medicine. I want to show you my table. Maybe you have an idea of how to fix my tables. I put the expiration date in tbl_received_order. When I received a medicine it will insert into tbl_medicine. What if the customer bought 50 pieces of paracetamol or supplier_med_id is equal to 3. And after two months the medicine received will be expired. I use DATE(NOW()) > tbl_received_order.expiration_date to get all the expired medicine.
My problem is that the qty is not tally to rec_qty when the medicine expired. Just for below example, I have 100 pcs. on my initial inventory. But later on, 50 pcs. was sold. Why is it 100 pcs.is still reflecting on my inventory of medicines for expiration, instead of 50pcs. How can I fix my table? Can somebody help me with my problem?
The is my table
tbl_medicine
med_id supplier_med_id qty status branch_id
1 3 50 Active 1
2 7 100 Active 1
3 9 100 Active 1
tbl_received_order
received_id user_id purchase_order_id date_received
RO20190001 1 PO20190001 2019-05-04
tbl_received_order_details
id received_id supplier_med_id rec_qty expiration_date
1 RO20190001 3 100 2019-11-04
2 RO20190001 7 100 2019-11-04
3 RO20190001 9 100 2019-11-04
1 RO20190002 3 50 2019-11-04
2 RO20190002 7 50 2019-11-04
3 RO20190002 9 50 2019-11-04
tbl_transaction
transaction_id customer_id user_id transaction_date branch_id
0001 CU2018001 1 2019-09-04 1
0002 CU2018001 1 2019-09-04 1
0003 CU2018001 1 2019-09-04 1
tbl_transaction_details
details_id transaction_id supplier_med_id qty price total_price
1 0001 3 50 10.00 500
2 0002 3 10 10.00 100
3 0003 3 10 10.00 100

You can get the accurate quantity by using a JOIN.
SELECT orderd.expiration_date, orderd.rec_qty - SUM(trans.qty) AS inventory_left
FROM tbl_received_order_details AS orderd
JOIN tbl_transaction_details AS trans
ON orderd.supplier_med_id = trans.supplier_med_id
WHERE orderd.supplier_med_id = 3
AND orderd.expiration_date < '2019-11-05'
Join tbl_received_order_details and tbl_transaction_details using supplier_med_id.
Filter the records with medicine id '3' and an expiration date.
Since there can be more than 1 transaction for a particular medicine, we need to SUM the quantity sold and subtract it from total quantity to get what's left.
Update 1
Above query will get expired medicines for the ones sold. To get quantity left for all inventories sold, use GROUP BY.
SELECT orderd.expiration_date, orderd.rec_qty - SUM(trans.qty) AS inventory_left
FROM tbl_received_order_details AS orderd
JOIN tbl_transaction_details AS trans
ON orderd.supplier_med_id = trans.supplier_med_id
WHERE orderd.expiration_date < '2019-11-05'
GROUP BY orderd.supplier_med_id
UPDATE 2
To get all left inventories that are expired whether they are sold or not, use LEFT JOIN. COALESCE(trans.qty, 0) will return first NOT NULL value. So if a medicine is never sold, it will not have any entry in transaction table which will return qty as NULL. In such cases, we will subtract zero from rec_qty which in turn will get complete rec_qty as left overs.
SELECT orderd.expiration_date, orderd.rec_qty - SUM(COALESCE(trans.qty, 0)) AS inventory_left
FROM tbl_received_order_details AS orderd
LEFT JOIN tbl_transaction_details AS trans
ON orderd.supplier_med_id = trans.supplier_med_id
WHERE orderd.expiration_date < '2019-11-05'
GROUP BY orderd.supplier_med_id

Related

Use aggregate functions with group by from several tables

I have the following tables to allow the subscriber to sell products through the application
Order Table
OrderId
Date
1
2021-07-10
2
2021-08-24
Approval table
ApprovalId
OrderId
Status
SellerId
1
1
Accepted
10
2
1
Rejected
20
3
2
Accepted
30
Item table
ItemId
OrderId
Price
Qty
SellerId
1
1
620$
1
10
2
1
150$
2
10
3
1
410$
1
20
4
2
220$
1
30
what i want is to display the income revenue for > only who accept the order
Date
Sales
Seller_Part 90%
Net_Sales 10%
2021-07-10
770$
693$
77$
2021-08-24
220$
198%
22$
I tried using aggregate functions with group by but the result include rejected order also
select o.date
,sum(i.price * i.qty) sales
,sum(i.price * i.qty) * 0.90 Seller_Part90%
,sum(i.price * i.qty) * 0.10 Net_Sales10%
from Order o
join Approval a
on o.orderId = a.OrderId
and a.status= 'Accepted'
join Items i
on a.sellerid = i.sellerid
and a.orderid = i.orderid
group by o.date

How to calculate price average while grouping by date in MySQL?

In MySQL 5.7 I need to calculate the average discount per merchant and day.
There are 2 tables:
produts_manufacturers:
PROD_ID | MANUFACTURER_ID | PRICE_RECOM
1 1 10
2 1 20
merchants_prices
PROD_ID | MERCHANT_ID | PRICE_ACTUAL | DATE
1 10 9.00 21-01-20
1 11 8.80 21-01-20
1 11 9.00 22-01-19
My goal is a chart that gets its metric value from group by DATE, merchant_id
Now how is it possible to calculate the average discount of all products from a manufacturer at a particular merchant without also grouping by PROD_ID?
SELECT
date,
merchant_id,
1- (t.PRICE_ACTUAL / p.PRICE_RECOM)*100 AS discount2
-- (1 - ROUND(AVG(PRICE_ACTUAL),2) / p.PRICE_RECOM)*100 AS discount
FROM
merchants_prices t
INNER JOIN produts_manufacturers p ON t.PROD_ID = p.PROD_ID
WHERE
p.MANUFACTURER_ID = 1
AND PRICE_ACTUAL IS NOT NULL
GROUP by
date,
MERCHANT_ID
ORDER BY
date desc, merchant_id
To calculate average discount per merchant and day:
SELECT `DATE`, MERCHANT_ID, ROUND(AVG(discount), 2) as discount
FROM (
SELECT mp.`DATE`, mp.MERCHANT_ID, 1- (mp.PRICE_ACTUAL / pm.PRICE_RECOM)*100 AS discount
FROM produts_manufacturers pm
JOIN merchants_prices mp ON mp.PROD_ID = pm.PROD_ID
-- WHERE pm.MANUFACTURER_ID = 1 -- If you want to restrict to a specific manufacturer
) as x
GROUP BY `DATE`, MERCHANT_ID;
With your dataset ->
DATE MERCHANT_ID discount
2021-01-20 10 -89
2021-01-20 11 -87
2022-01-19 11 -89
To help you I made a fiddle here

How can I get the quantity both expired and not yet expired?

I subtract the quantity of expired medicine to the actual stock. I use this (IFNULL(tbl_medicine.quantity - SUM(tbl_received.received_quantity),0)) AS Total and DATE(NOW()) > tbl_received.expiration_date to get the date of expired medicine. My problem is I can't get the quantity that is not expired yet. How can I get the quantity of not yet expired with expired medicine? Can somebody help me with my problem? Here's my query...
SELECT tbl_med.sup_med_id, tbl_med.quantity,
tbl_received.received_quantity, tbl_med.status,
(IFNULL(tbl_med.quantity - SUM(tbl_received.received_quantity),0)) AS Total
FROM
tbl_med
INNER JOIN
tbl_received ON tbl_received.sup_med_id = tbl_med.sup_med_id
WHERE
tbl_med.status = 'Active' AND DATE(NOW()) > tbl_received.expiration_date AND
tbl_med.barangay_id = 19
GROUP BY
sup_med_id HAVING Total > 0
ORDER BY
sup_med_id
output of query above
sup_med_id quantity received_quantity status Total
3 1800 1000 Active 800
7 1800 1000 Active 800
tbl_med & tbl_received table
id sup_med_id received_quantity expiration_date
1 3 1000 2019-09-04
2 7 1000 2019-09-04
3 9 1800 2022-09-04
medicine_id sup_med_id quantity status barangay_id
1 3 1800 Active 19
2 7 1800 Active 19
3 9 1800 Active 19
I want this to happen...
sup_med_id quantity received_quantity status Total
3 1800 1000 Active 800
7 1800 1000 Active 800
9 1800 1800 Active 1800
I just want to display the quantity to Total if the medicine is not expired yet
The issue comes from the fact you're only joining when the expiration date is in the past. To solve it that check should be removed from the WHERE clause and done in the SUM of expired quantities instead:
SELECT tbl_med.sup_med_id, tbl_med.quantity,
tbl_received.received_quantity, tbl_med.status,
(tbl_med.quantity
- SUM(CASE WHEN NOW() > tbl_received.expiration_date
THEN tbl_received.received_quantity
ELSE 0
END)
) AS Total
FROM
tbl_med
INNER JOIN
tbl_received ON tbl_received.sup_med_id = tbl_med.sup_med_id
WHERE
tbl_med.status = 'Active' AND
tbl_med.barangay_id = 19
GROUP BY
sup_med_id HAVING Total > 0
ORDER BY
sup_med_id
I haven't tested the query myself, but I believe it should achieve what you want

MySQL join next lower value from other table

I've the two tables orders
id article amount
1 1 1
2 2 50
and prices
id article min_amount price
1 1 1 42.99
2 2 1 5.06
3 2 5 4.55
4 2 10 4.3
5 2 25 4.05
6 2 100 2.66
The prices tables contains IDs of articles and a minimum amount you would have to buy to get a bulk discount (which would change the price for the order). I would like to join prices into orders, so that the result looks like:
id article amount price
1 1 1 42.99
2 2 50 4.05
The order id 2 is above the minimum (25) to get the article for 4.05€, but still below 100 at which you would get a bigger discount, so the query would to have pick the next-lower value.
I've tried this query so far
SELECT
orders.id AS id,
orders.article,
orders.amount,
prices.price,
(orders.amount - prices.min_amount) AS discount_diff
FROM orders
LEFT JOIN prices ON (prices.article = orders.article) AND (prices.min_amount <= orders.amount)
which gives this result
id article amount price discount_diff
1 1 1 42.99 0
2 2 50 5.06 49
2 2 50 4.55 45
2 2 50 4.3 40
2 2 50 4.05 25
You can find this example on "js"fiddle: http://sqlfiddle.com/#!9/1b2bf/8
The query you need is this:
SELECT orders.id AS id,
orders.article,
orders.amount,
prices.price
FROM orders
INNER JOIN prices ON ( prices.article = orders.article
and prices.min_amount <= orders.amount)
INNER JOIN ( SELECT orders.article,
orders.amount,
min(prices.price) minprince
FROM orders
INNER JOIN prices ON (prices.article = orders.article
AND prices.min_amount <= orders.amount)
GROUP BY orders.article,
orders.amount) b
ON ( prices.article = b.article
AND orders.amount = b.amount
AND prices.price = b.minprince)
See it here: http://sqlfiddle.com/#!9/1b2bf/27

MySQL sum amounts for transactions related to loans, in reverse order

I'm trying to add an amount living in a transactions table, but the adding must be done taking the transactions in reversed order, grouped by a loan they belong to. Let me put some examples:
Transactions
tid loanid amount entrydate
------------------------------------
1 1 1,500 2013-06-01
2 2 1,500 2013-06-01
3 1 1,000 2013-06-02
4 3 2,300 2013-06-04
5 5 2,000 2013-06-04
6 1 1,100 2013-06-07
7 2 1,000 2013-06-09
| | | |
Loans
loanid
------
1
2
3
4
5
|
As you can see, there's no transactions for loanid 4, just to make clear the point that there's no obligation for the transactions to exist for every loan.
Now, what I'm trying to achieve is to sum up the amounts for the transactions of each loan. This first approach achieves this:
SELECT tr.tid,
l.loanid,
tr.entrydate,
tr.amount,
#prevLoan:=l.loanid prevloan,
#amnt:=if(#prevLoan:=l.loanid, #amnt+tr.amount, tr.amount) totAmnt
FROM (SELECT * FROM Transactions) tr
JOIN (SELECT #prevLoan:=0, #amnt:=0) t
JOIN Loans l
ON l.loanid = tr.loanid
GROUP BY l.loanid, tr.tid
Which achieves something like this:
tid loanid entrydate amount prevloan totAmnt
-----------------------------------------------------------
1 1 2013-06-01 1,500 1 1,500
3 1 2013-06-02 1,000 1 2,500
6 1 2013-06-07 1,100 1 3,600 <-- final result for loanid=1
2 2 2013-06-01 1,500 2 1,500
7 2 2013-06-09 1,000 2 2,500 <-- final result for loanid=2
4 3 2013-06-04 2,300 3 2,300 <-- final result for loanid=3
5 5 2013-06-04 2,000 5 2,000 <-- final result for loanid=5
| | | | | |
As you can see, for each loan, the amount of the transactions belonging to it are getting sumed up in the totAmnt column, so the last transaction of each loan has the total sum of the transactions for the same loan.
Now.... what I actually need is something to get the sum to be done in reversed order. I mean, for the same transactions of each loan, the sum still gets the same result, but I need the sum to be done from the last transaction of each loan up to the first one.
I've tried the following, but to no avail (it's the same query as the last one, but with an Order By DESC on the FROM transactions table):
SELECT tr.tid,
l.loanid,
tr.entrydate,
tr.amount,
#prevLoan:=l.loanid prevloan,
#amnt:=if(#prevLoan:=l.loanid, #amnt+tr.amount, tr.amount) totAmnt
FROM (SELECT * FROM Transactions ORDER BY tr.entrydate DESC) tr
JOIN (SELECT #prevLoan:=0, #amnt:=0) t
JOIN Loans l
ON l.loanid = tr.loanid
GROUP BY l.loanid, tr.tid
I'm using tr.entrydate because is a more familiar way to say the order criteria, and besides that's what policy says is the valid order criteria, tid may say something but entrydate is the ordering column of the Transactions table...
Using the previous query, I just get the same results I get with the first query, so I guess something must be missing there. What I need is to get results as the following:
tid loanid entrydate amount prevloan totAmnt
-----------------------------------------------------------
6 1 2013-06-07 1,100 1 1,100
3 1 2013-06-02 1,000 1 2,100
1 1 2013-06-01 1,500 1 3,600 <-- final result for loanid=1
7 2 2013-06-09 1,000 2 1,000
2 2 2013-06-01 1,500 2 2,500 <-- final result for loanid=2
4 3 2013-06-04 2,300 3 2,300 <-- final result for loanid=3
5 5 2013-06-04 2,000 5 2,000 <-- final result for loanid=5
| | | | | |
As you can see the sum for each loanid gets the same final result, but the sum is done for the transactions in reversed order...
Hope all this mess is clear... How can I achieve such a result?
You appear to be VERY close... I think you have two small adjustments. First, dont use the outer GROUP BY as you are not doing any aggregations (sum, min, max, avg, etc). Second, when querying your transaction table, just order that by the loan ID FIRST, THEN the date descending... This way all the loan IDs are in proper order grouped together, but within each loan, THEY are sorted descending order as you are looking for. Also, adjust your #prevLoan AFTER you have accumulated so the current record can be compared to the next. You are starting the #variable to zero so it won't match the first loan ID on the first run anyhow. Finally, you don't even need the join to the loan table since the transaction table has the loan ID to use as basis of comparison test. Since the inner-most query is ordered by loan and then entry date descending, you should not need it again at the outer query.
SELECT
tr.tid,
tr.loanid,
tr.entrydate,
tr.amount,
#amnt := if( #prevLoan = tr.loanid, #amnt+tr.amount, tr.amount) totAmnt,
#prevLoan := tr.loanid prevloan
FROM
( SELECT *
FROM Transactions
ORDER BY loanid, entrydate DESC) tr
JOIN (SELECT #prevLoan := 0,
#amnt := 0) t
Alternate Solution?? Per my comment, it looks like you want the high totals and shrinking down... Is this closer?
SELECT
tr.tid,
tr.loanid,
tr.entrydate,
tr.amount,
trTotals.TotalLoans - if( #prevLoan = tr.loanid, #amnt, 0 ) as NewBal,
#amnt := if( #prevLoan = tr.loanid, #amnt+tr.amount, tr.amount) runningTotals,
#prevLoan := tr.loanid prevloan
FROM
( SELECT *
FROM Transactions
ORDER BY loanid, entrydate DESC) tr
JOIN ( SELECT loanid, sum( amount ) as TotalLoans
FROM Transactions
group by loanid ) trTotals
on tr.loanid = trTotals.loanid
JOIN (SELECT #prevLoan := 0,
#amnt := 0) t
Produces... (Total Paid) (for reversing calc)
tid loanid entrydate amount NewBal Running Totals prevLoan
6 1 2013-06-07 1100 3600 1100 1
3 1 2013-06-02 1000 2500 2100 1
1 1 2013-06-01 1500 1500 3600 1
7 2 2013-06-09 1000 2500 1000 2
2 2 2013-06-01 1500 1500 2500 2
4 3 2013-06-04 2300 2300 2300 3
5 5 2013-06-04 2000 2000 2000 5