I would like to ask how to use the FIFO method with MYSQL8 to generate the expected result as follow.
The date of the stock in the result table must be the stock in date. Thanks to everyone if you can help.
Orginal_Table
Stock Name
In/out
Quantity
Date
Apple
in
10
1/1/2021
Banana
in
5
1/2/2021
Banana
out
3
1/5/2021
Banana
in
4
1/6/2021
Cherry
in
3
1/6/2021
Cherry
in
4
1/7/2021
Cherry
out
5
1/8/2021
Expected_result
Stock Name
balance
stock_in_date
Apple
10
1/1/2021
Banana
2
1/2/2021
Banana
4
1/6/2021
Cherry
2
1/7/2021
WITH
cte1 AS (
SELECT name, SUM(quantity * (operation = 'out')) went_out
FROM test
GROUP BY name
),
cte2 AS (
SELECT *, SUM(quantity * (operation = 'in')) OVER (PARTITION BY name ORDER BY operation_date) amount
FROM test
)
SELECT name,
operation_date,
CASE WHEN amount - quantity < went_out
THEN amount - went_out
ELSE quantity
END result
FROM cte1
JOIN cte2 USING (name)
WHERE operation = 'in'
AND went_out < amount
ORDER BY 1,2;
fiddle with query building steps.
Related
I'm new to SQL and I have two tables with a many-to-many relationship. I know the math behind the calculation by am unable to transfer it into SQL language
Tables:
Table A like:
Item Name
Effective Date
Cancelled Date
Unit Price
Book
2010-01-02
2021-12-21
10
Book
2022-01-01
2028-01-01
15
Ice Cream
2018-01-01
2028-01-01
4
Table B like:
Item Name
Sales Date
Volume
Discounted Price
Book
2019-01-01
8
70
Book
2022-01-01
5
75
Ice Cream
2020-12-01
10
30
I want to calculate how much money each Item saved each month due to promotion, so my output should be:
Item Name
Month
MoneySaved
I came up with the following structure:
select a.price as price_at_that_time
from TableA join TableB on a.ItemName = b.ItemName
where SalesDate between EffectiveDate and CancelledDate
select to_char(SalesDate, 'YYYY-MM') as month,
a.ItemName,
sum(price_at_that_time * SalesVolume - discounted price) as MoneySaved
from TableA join TableB ...
group by to_char(SalesDate, 'YYYY-MM'),
a.fitm
However, I'm not able to combine these two steps into one because of the many to many relationship and the dynamic nature of the price. Items may have different unit prices in different months, and even within a month, the unit price can be different.
I tired code like:
select to_char(SalesDate, 'YYYY-MM') as month,
a.ItemName,
sum(a.UnitPrice * SalesVolume - DiscountedPrice) as MoneySaved
from TableA join TableB on a.ItemName = b.ItemName
where a.UnitPrice in
(select a.UnitPrice from TableA join TableB on a.ItemName = b.ItemName where SalesDate between EffectiveDate and CancelledDate)
group by to_char(SalesDate, 'YYYY-MM'),
a.fitm
I know the code is wrong but that's closest I can get.
Almost exactly as you described it:
With TableA as (
select *
from (values
('Book', '2010-01-02', '2021-12-21', 10)
,('Book', '2022-01-01', '2028-01-01', 15)
,('Ice Cream', '2018-01-01','2028-01-01', 4)
) T(ItemName,EffectiveDate,CancelledDate, UnitPrice)
)
, TableB as (
select *
from (values
('Book' ,'2019-01-01' ,8 ,70)
,('Book' ,'2022-01-01' ,5 ,75)
,('Ice Cream' ,'2020-12-01' ,10 ,30))
T(ItemName,SalesDate,Volume,DiscountedPrice)
)
select
Sales.ItemName
, sum((RegPRices.UnitPrice * Sales.Volume) -
Sales.DiscountedPrice) as SavedAmount
from
TableB as Sales
inner join
TableA RegPrices
on RegPrices.ItemName=Sales.ItemName
and Sales.SalesDate
between RegPrices.EffectiveDate and RegPrices.CancelledDate
group by Sales.ItemName
This returns:
ItemName
SavedAmount
Book
10
Ice Cream
10
.
So basically as an example, here's a table of foods and the date they were consumed on by different people
consumption
user_id
food
date
1
apple
12-DEC-09
1
banana
12-DEC-09
1
strawberry
13-DEC-09
2
apple
14-DEC-09
2
apple
15-DEC-09
2
orange
15-DEC-09
I want to select all foods that each user_id ate on each unique date, so the output looks something like:
user_id
food
date
1
apple, banana
12-DEC-09
1
strawberry
13-DEC-09
2
apple
14-DEC-09
2
apple, orange
15-DEC-09
I've tried something like this:
SELECT food
FROM consumption
WHERE food IN (
SELECT food
FROM consumption
GROUP BY food, `date`
)
GROUP BY user_id;
But I'm stumped. Any help would be appreciated!
The group in your case is rows group where both user_id and date is the same. Hence you must group by these two columns.
You need all food names concatenated into single value within a group. Hence you must use according aggregate function.
SELECT user_id, GROUP_CONCAT(food) food_list, `date`
FROM consumption
GROUP BY user_id, `date`;
I am clueless how can I write a (MySQL) query for this. I am sure it is super simple for an experienced person.
I have a table which summarizes sold items per day, like:
date
item
quantity
2020-01-15
apple
3
2020-01-15
pear
2
2020-01-15
potato
1
2020-01-14
orange
3
2020-01-14
apple
2
2020-01-14
potato
2
2020-01-13
lemon
5
2020-01-13
kiwi
2
2020-01-13
apple
1
I would like to query the N top sellers for every day, grouped by the date DESC, sorted by date and then quantity DESC, for N = 2 the result would look like:
date
item
quantity
2020-01-15
apple
3
2020-01-15
pear
2
2020-01-14
orange
3
2020-01-14
apple
2
2020-01-13
lemon
5
2020-01-13
kiwi
2
Please tell me how can I limit the returned item count per date.
First of all, it is not a good idea to use DATE as the name of a column.
You can use #rank := IF(#current = date, #rank + 1, 1) to number your rows by DATE. This statement checks each time that if the date has changed, it starts counting from zero.
Select date, item, quantity
from
(
SELECT item, date, sum(quantity) as quantity,
#rank := IF(#current = date, #rank + 1, 1) as ranking,
#current := date
FROM yourtable
GROUP BY item, date
order by date, sum(quantity) desc
) t
where t.ranking < 3
You can do this if you are using MySQL 8.0++
SELECT * FROM
(SELECT DATE, ITEM, QUANTITY, ROW_NUMBER() OVER (PARTITION BY DATE ORDER BY QUANTITY DESC) as order_rank FROM TABLE_NAME) as R
WHERE order_rank < 2
I think you can use:
select t.*
from t
where (quantity, item) >= (select t2.quantity, t2.item
from t t2
where t2.date = t.date
order by t2.quantity desc, t2.item
limit 1 offset 1
);
The only caveat is that you need to have at least "n" items available on the day (although that condition can be added as well).
I have a table T1 with 3 columns: ProductBrand, PurchasedDate, SoldDate. ProductBrand represents the brand of the product. PurchasedDate contains the date (in format yyyy-mm) when we purchased a product and SoldDate contains the date (again in yyyy-mm) when we sold this product. For example:
ProductBrand PurchasedDate SoldDate
----------------------------------
Apple 2015-03 2015-05
Samsung 2014-01 2015-03
Sony 2016-02 2016-05
Sony 2013-01 2013-08
Apple 2015-05 2015-10
LG 2011-02 2014-06
Samsung 2017-02 2017-04
LG 2016-01 2016-06
LG 2018-06 2019-01
I would like a table that counts for each brand and for each month (between the years 2010-01 and 2019-12) how many products of this specific brand I had for this particular month in the inventory. Namely, in this example, I have two Apple products. The first one stayed in the inventory between 2015-03 and 2015-06 and the second one stayed in the inventory between 2015-04 and 2015-08. So I expect a table that has:
ProductBrand YearMonthDate NitemsInventory
------------ ------------ -------------------
Apple 2010-01 0
Apple 2010-02 0
... ... ...
Apple 2015-03 1
Apple 2015-04 2
Apple 2015-05 2
Apple 2015-06 2
Apple 2015-07 1
Apple 2015-08 1
Apple 2015-09 0
... ... ...
Apple 2019-12 0
In the same table I would like to have all the brands in the same fashion as Apple. So if we have n different brands and t is the number of months between (2010-01 and 2019-12), the end array will have n times t rows. In other words, I would like see for each month the number of items that I had in the inventory for each brand.
I am using mysql and I suppose I have tried to groupby the column ProductBrand of T1. However, this does not give what I expect.
We can do this with some big ugly calendar tables:
SELECT
t.ProductBrand,
d.YearMonthDate,
COUNT(t.ProductBrand) AS NitemsInventory
FROM
(
SELECT DISTINCT ProductBrand FROM yourTable
) AS p
CROSS JOIN
(
SELECT '2010-01' AS YearMonthDate UNION ALL
SELECT '2010-02' UNION ALL
SELECT '2010-03' UNION ALL
...
SELECT '2015-03' UNION ALL
SELECT '2015-04' UNION ALL
...
SELECT '2019-12'
) AS d
LEFT JOIN yourTable t
ON d.YearMonthDate BETWEEN t.PurchasedDate AND t.SoldDate AND
p.ProductBrand = t.ProductBrand
WHERE
t.productBrand IS NOT NULL
GROUP BY
t.ProductBrand,
d.YearMonthDate;
Here is a demo which shows the query in action:
Demo
I have a sql table like :
id buy_product buy_product_total sell_product sell_product_total
1 apple 5
2 banana 8
3 cake 20
4 apple 1
5 cake 2
6 apple 2
My problem is, I want to show product name and how many product left. Like :
product_name left
apple 6
cake 18
How can I show like that solution with sql query ?
I create table as answerers as :
Buy Table
id product_name total
1 apple 5
2 banana 8
3 cake 20
4 apple 2
Sell Table
id product_name total
1 apple 1
2 cake 2
I want to table like this
product_name left
apple 6
banana 8
cake 18
Is not a good table, could be better that buy and sell to be the same collumn buy with positive values and sell with negative.
But answer your question, suppose that your table name is myTable,
obs: you can execute every select separeted to understand better
select buy_product as product_name, (buy_total - sell_total) as left
from (
(select buy_product, sum(buy_product_total) as buy_total
from myTable where buy_product_total is not null group by buy_product) as buy_list
inner join
(select sell_product, sum(sell_product_total) as sell_total
from myTable where sell_product_total is not null group by sell_product) as sell_list
on buy_list.buy_product = sell_list.sell_product
)
As others have noted, your table structure is less than optimal.
However, given what you have, this will give you the results you're after.
select product, sum(total) from
(
select buy_product as product, buy_product_total as total
from yourtable
where buy_product is not null
union
select sell_product, -sell_product_total
from yourtable
where sell_product is not null
) v
group by product
Or, with your two tables
select product_name, sum(total) from
(
select product_name, total
from buy_table
union
select product_name, -total
from sell_table
) v
group by product_name
You should consider a different database design that is more appropriate (You may want to read up on normalization), but query follows:
SELECT t1.buy_product_total - t2.sell_product_total
FROM ProductTable t1, ProductTable t2
WHERE t1.buy_product = t2.sell_product
i.e. You're joining the table to itself using a 'self join'...