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
Related
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
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
I have 2 tables
article_receive , which records the the receiving via following columns;
item | title |trans_id |qty|price|current_items | current_value
ADN231 | 12" Valve |jvn2333 |24 | 175 | 24 | 4200
ADN231 | 12" Valve |jvn2388 |12 | 185 | 36 | 6420
Current Items is always total of all items
Current Value is value of all transaction combined (4200 + 2220)
For Issuance , i have article_issue with following columns;
item | title | trans_id | qty
ADN231 | 12" Valve | ISU2333 | 6
ADN231 | 12" Valve | ISU2401 | 24
My requirement is , that i want to create a consumption report, which basically calculates the exact amount of items on every issuance using FIFO method.
2nd row in article_issue has items from 2 transactions and has 2 different prices. How to calculate it in MYSQL 8.0.15 Community Version.
Currently, i am using this SQL Statement;
SELECT
article_receives.id as RCVID, article_receives.item_id, article_receives.item_title, article_receives.quantity as rcv_qty,article_receives.transaction_id, article_receives.price as rate,
article_issues.id as ISUID,article_issues.quantity as isu_qty, article_issues.quantity * article_receives.price as value
FROM article_receives
LEFT JOIN article_issues ON article_receives.item_id = article_issues.item_id
ORDER BY article_receives.item_id
/** Some Column names are changed */
This gives me data in following state;
Please help me out in creating a proper consumption report in mysql.
On side note, This is an app developed in laravel 5.8 , so eloquent is also available.
Thanks
Thanks to P.Salmon provided link FIFO i was able to solve the problem.
MySql Query is :
WITH
running_purchase AS
( SELECT transaction_id, created_at, quantity, item_id, price,
SUM(quantity) OVER (PARTITION BY item_id
ORDER BY created_at, transaction_id
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AS running_total
FROM article_receives
),
running_stock AS
( SELECT demand_id, created_at, quantity, item_id,
SUM(quantity) OVER (PARTITION BY item_id
ORDER BY created_at, demand_id
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AS running_total
FROM article_issues
)
SELECT
s.demand_id, p.transaction_id,p.created_at as purchase_date, p.item_id, p.price, s.created_at as issue_date,
LEAST(p.running_total, s.running_total)
- GREATEST(s.running_total - s.quantity, p.running_total - p.quantity)
AS quantity
FROM running_purchase AS p
JOIN running_stock AS s
ON p.item_id = s.item_id
AND s.running_total - s.quantity < p.running_total
AND p.running_total - p.quantity < s.running_total
WHERE s.created_at BETWEEN '2019-06-01' AND DATE_ADD('2019-06-30', INTERVAL 1 DAY)
ORDER BY
p.item_id, p.created_at, p.transaction_id ;
I am trying to find a way to get the largest price difference (in a time frame, e.g. 24 hours) in a MySQL table using a source and productId as reference.
Here is a sample product, productId 22.
id price createdAt updatedAt sourceId productId
21 799.00 2017-07-26 19:46:46 2017-07-26 19:46:45 1 22
853 920.00 2017-07-26 06:46:46 2017-07-26 06:46:46 1 22
855 799.00 2017-07-22 16:17:11 2017-07-22 16:17:11 2 22
851 770.00 2017-07-21 16:17:11 2017-07-21 16:17:11 1 22
856 799.00 2017-07-20 16:17:11 2017-07-20 16:17:11 2 22
852 599.00 2017-07-19 16:17:11 2017-07-19 16:17:11 1 22
857 810.00 2017-07-18 16:17:11 2017-07-18 16:17:11 2 22
858 799.00 2017-07-17 16:17:11 2017-07-17 16:17:11 2 22
In the example above for productId 22 I am sorting by createdAt, so in this scenario I'd take id 21 and substract it from id 853, this would give -121, meaning the product went down 121 dollars.
In the full data it's a mush up of prices, sourceIds and productIds. The goal here is to make a result look like this:
id createdAt sourceId productId adjustment
21 2017-07-26 19:46:46 1 22 -121
22 2017-07-26 16:46:46 2 22 201
23 2017-07-26 15:46:46 6 24 -20
Above is kind of how I am trying to get the data to look, so I'll know of the price difference of each product of each source. Then I can control the data, such as ordering by adjustment and seeing which source + product had the largest decrease or increase in a time frame.
I've tried doing a ton of sub-queries, I've probably put in a hundred examples that I've modified from Google. I can piece together parts of this, such as only getting products that have recieved a change of any kind from the past 24 hours. I've tried to merge the last two rows of each product Id, then do a math, and list all the products. It's been 2 days of trying to build this query, is it just best for me to not use queries for everything and do it on my backend?
I've even went to a support site like hackhands and they couldn't figure it out. I've exhausted all of my ideas.
This query breaks down the problem:
1) Getting the records corresponding to start_at time of the window for each product in order to get the baseline price.
2) Gets the the records for the max price for each product in the time frame.
3) Gets the records for the min price for each product in the time frame.
4) Combines 1 and 2 and 3 to form a single record per product and shows the info and the difference between base line price and the highest and lowest in the time frame.
If you only need the bigger of the two you can add and extra layer of select wrapping this query and user GREATER(a,b) to keep one diff or the other.
select BOWPRICE.product_id, BOWPRICE.created_at, BOWPRICE.price,
MAXPRICE.max_price_upd_time, MAXPRICE.max_price, ABS((BOWPRICE.price - MAXPRICE.max_price)) max_price_diff,
MINPRICE.min_price_upd_time, MINPRICE.min_price, ABS((BOWPRICE.price - MINPRICE.min_price)) min_price_diff
from
(
select mainA.product_id, mainA.created_at, mainA.price from SOTEST mainA
where id in (
select id
from SOTEST N
where created_at = (
select min(N1.created_at)
from SOTEST N1
where N1.created_at >= '2017-07-26 00:00:00'
and N1.product_id = N.product_id
)
group by mainT.product_id
)
) BOWPRICE,
(
select mainB.product_id, mainB.updated_at max_price_upd_time, mainB.price max_price from SOTEST mainB
where id in(
select id from SOTEST M
where M.price = (
select max(M1.price)
from SOTEST M1
where M1.created_at >= '2017-07-26 00:00:00'
and M1.created_at < '2017-07-27 00:00:00'
and M1.product_id = M.product_id
group by product_id LIMIT 1
)
)
) MAXPRICE,
(
select mainC.product_id, mainC.updated_at min_price_upd_time, mainC.price min_price from SOTEST mainC
where id in(
select id from SOTEST Q
where Q.price = (
select min(Q1.price)
from SOTEST Q1
where Q1.created_at >= '2017-07-26 00:00:00'
and Q1.created_at < '2017-07-27 00:00:00'
and Q1.product_id = Q.product_id
group by product_id LIMIT 1
)
)
) MINPRICE
where BOWPRICE.product_id = MAXPRICE.product_id
and BOWPRICE.product_id = MINPRICE.product_id
I've been searching for answers for 2 day and still nothing. Please, help me.
I have a database with products, product's prices and the date when this prices were registered:
product_id | price | date
-------------------------
1 | 8.95 | 2012-12-01
2 | 3.40 | 2012-12-01
1 | 9.05 | 2012-12-19
3 | 2.34 | 2012-12-24
3 | 2.15 | 2012-12-01
1 | 8.80 | 2012-12-19
1 | 8.99 | 2012-12-02
2 | 3.45 | 2012-12-02
Observe that is possible to have different price values for a product on the same day (rows 3 and 6). This is because there are many suppliers for a single product. There is a supplier column on database too, but I found it irrelevant for the solution. You can add it to the solution if I'm wrong.
Basically what I want is to write a query that returns two combined sets of data, as follow:
First set is made by minimum price of products inserted in the last month. As today is jan, 15, query should read rows 3, 4 and 6, apply the minimum price, and return only rows 4 and 6, both with minimum price for that product on the last month.
Second set is made by last products inserted, with no price registered on last month. i.e, for products not shown in the first set, query should search for the last inserted ones.
I hope that is clear. Ask me more if it isn't.
The query result for this database should be:
product_id | price | date
-------------------------
1 | 8.80 | 2012-12-19 <-Min price for product 1 on last month
3 | 2.34 | 2012-12-24 <-Min price for product 3 on last month
2 | 3.45 | 2012-12-02 <-No reg for product 2 on last month, show last reg.
I've tried everything: UNION, (DATE_SUB(CURDATE(), INTERVAL 1 MONTH), MIN(price), MAX(date) etc, etc. Nothing works. I don't know where to search now, please help me.
(SELECT product_id, MIN(price), date
FROM products
WHERE date + INTERVAL 1 MONTH > NOW()
GROUP BY product_id)
UNION
(SELECT product_id, price, MAX(date)
FROM products
WHERE product_id NOT IN (SELECT product_id
FROM products
WHERE date + INTERVAL 1 MONTH > NOW()
GROUP BY product_id)
GROUP BY product_id)
This should work but I'm not sure it's the most optimized way to do it.
something like this will do the trick:
SELECT * FROM (
SELECT DISTINCT b.product_id, IF (c.min IS NULL,(SELECT ROUND(e.price,2) FROM products AS e WHERE e.product_id = b.product_id ORDER BY e.date DESC LIMIT 1 ),c.min) AS min, IF (c.date IS NULL,(SELECT f.date FROM products AS f WHERE f.product_id = b.product_id ORDER BY f.date DESC LIMIT 1 ),c.date) AS date, IF(c.min IS NULL,'<-No reg for product 2 on last month, show last reg.','<-Min price for product 1 on last month') as text FROM products AS b
LEFT JOIN
(SELECT a.product_id, round(MIN(a.price),2) AS min, a.date FROM products AS a WHERE a.date BETWEEN DATE_SUB(CURDATE(), INTERVAL 1 MONTH) AND CURDATE() GROUP BY a.product_id) AS c
ON (b.product_id = c.product_id)
) AS d
ORDER BY d.text, d.product_id
Gives output:
product_id|min|date|text
1|8.80|2012-12-19|<-Min price for product 1 on last month
3|2.34|2012-12-24|<-Min price for product 1 on last month
2|3.45|2012-12-02|<-No reg for product 2 on last month, show last reg.
Break it down into several sub-queries:
Products with prices in the last month, min price
join in date for that price
UNION
Products with no-prices in the last month, max date
join in price on that date
SQL Fiddle
Here
Query
SELECT MINPRICE.product_id, P.date, MINPRICE.price
FROM
(
-- Min price in last 31 days
SELECT product_id, MIN(price) AS price
FROM Prices
WHERE DATEDIFF(CURDATE(), date) < 31
GROUP BY product_id
) MINPRICE
-- Join in to get the date that the price occured on
INNER JOIN Prices P ON
P.product_id = MINPRICE.product_id
AND
P.price = MINPRICE.price
UNION
SELECT MAXDATE.product_id, MAXDATE.date, P.price
FROM
(
-- Product with no price in last 31 days - get most recent date
SELECT product_id, MAX(date) AS date
FROM Prices
WHERE product_id NOT IN
(
SELECT product_id
FROM Prices
WHERE DATEDIFF(CURDATE(), date) < 31
)
) MAXDATE
-- join in price on that date
INNER JOIN Prices P ON
P.product_id = MAXDATE.product_id
AND
P.date = MAXDATE.date
Not that I tested but you can try...
SELECT * FROM
(SELECT * FROM (
SELECT * FROM table ORDER BY date DESC)
as tmp GROUP BY product_id) t1
LEFT JOIN
(SELECT * FROM (
SELECT * FROM table WHERE date => CURDATE() ORDER BY price)
as tmp2 GROUP BY product_id) t2
ON t1.product_id = t2.product_id