Need mysql query FIFO - mysql

please help me how to create mysql query for reporting in fifo method,
table persediaan_source
id
id_barang
jumlah
harga
tanggal
id_jenis_transaksi
89
26
12
1050000
2022-07-15 05:55:23
1
90
26
8
0
2022-07-15 05:55:52
2
91
26
16
1100000
2022-07-15 05:56:22
1
95
26
10
0
2022-07-15 05:59:09
2
id_jenis_transaksi = 1 is Buy
id_jenis_transaksi = 2 is Use
i need report like this below
id
date
remarks
buy_qty
buy_price
buy_total
use_qty
use_qty_detail
use_price
use_total
bal_qty
bal_qty_detail
bal_price
bal_total
1
2022-07-15 05:55:23
Buy
12
1050000
12600000
0
0
0
0
12
12
1050000
12600000
2
2022-07-15 05:55:52
Use
0
0
0
8
8
1050000
8400000
4
4
1050000
4200000
3
2022-07-15 05:56:22
Buy
16
1100000
17600000
0
0
0
0
20
4
1050000
4200000
4
2022-07-15 05:56:22
Buy
0
0
0
0
0
0
0
0
16
1100000
17600000
5
2022-07-15 05:59:09
Use
0
0
0
10
4
1050000
4200000
10
0
1050000
0
6
2022-07-15 05:59:09
Use
0
0
0
0
6
1100000
6600000
0
10
1100000
11000000
in row #3 must be breakdown in bal_qty_detail because there is a different price and have a remaining qty from a previous price, also in row #5 must be breakdown in use_qty_detail
CREATE TABLE `persediaan_source` (
`id` int(11) NOT NULL,
`id_barang` int(11) NOT NULL,
`jumlah` double NOT NULL,
`harga` double NOT NULL,
`tanggal` datetime NOT NULL,
`id_jenis_transaksi` tinyint(4) NOT NULL COMMENT 'id = 1 -> buy, id = 2 -> use'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `persediaan_source` (`id`, `id_barang`, `jumlah`, `harga`, `tanggal`, `id_jenis_transaksi`) VALUES
(89, 26, 12, 1050000, '2022-07-15 05:55:23', 1),
(90, 26, 8, 0, '2022-07-15 05:55:52', 2),
(91, 26, 16, 1100000, '2022-07-15 05:56:22', 1),
(95, 26, 10, 0, '2022-07-15 05:59:09', 2);

Hi using the below process you can achieve the mention reporting format. But to handle the granularity of fifo you should aviod creating these logic in mysql.
SELECT #bal_qty:=0,#old_qty:=0,#old_qty_price:=0,#new_qty:=0,#new_qty_price:=0;
CREATE TEMPORARY TABLE test1
SELECT id, tanggal as date,
#remarks:=if(id_jenis_transaksi=1,'Buy','Use') as remarks,
#buy_qty:=if(id_jenis_transaksi=1,jumlah,0) as buy_qty,
#buy_price:=if(id_jenis_transaksi=1,harga,0) as buy_price,
#buy_total:=(#buy_qty * #buy_price) as buy_total,
#use_qty:=if(id_jenis_transaksi=2,jumlah,0) as use_qty,
#use_qty_detail:=if(#remarks='Use',if(#old_qty>0,#old_qty, #use_qty),0) as use_qty_detail,
#use_price:=#old_qty_price as use_price,
#use_total:=(#use_qty * #use_price) as use_total,
#bal_qty:=if(#remarks='Buy',#bal_qty + #buy_qty, if(#bal_qty>#use_qty,#bal_qty - #use_qty, #bal_qty)) as bal_qty,
#old_qty:=if(#old_qty > 0, #old_qty, if(#remarks='Use',#bal_qty, #old_qty)) as old_qty,
#old_qty_price:=if(#old_qty_price > 0, #old_qty_price, #buy_price) as old_qty_price,
#new_qty:=if(#old_qty>0,#buy_qty, if(#new_qty>0, #new_qty,0)) as new_qty,
#new_qty_price:=if(#old_qty_price > 0 and #buy_price > 0, #buy_price, if(#new_qty_price>0,#new_qty_price,0)) as new_qty_price,
#bal_qty_detail:=if(#old_qty > 0, #old_qty, #buy_qty) as bal_qty_detail,
#bal_price:=#old_qty_price as bal_price,
#bal_total:=(#bal_qty_detail* #old_qty_price) as bal_total,
#split_flag:=if(#bal_qty != #buy_qty and #bal_qty != #old_qty,1,0) as split_flag
FROM persediaan_source;
CREATE TEMPORARY TABLE test2 select * from test1 where split_flag=1
SELECT #cnt:=0;
SELECT (#cnt:=#cnt + 1) as id, date, remarks, buy_qty, buy_price, buy_total, use_qty, use_qty_detail, use_price, use_total, bal_qty, bal_qty_detail, bal_price, bal_total
FROM (
(SELECT * FROM test1)
UNION ALL
(SELECT id, date, remarks, 0 as buy_qty, 0 as buy_price, 0 as buy_total, 0 as use_qty,
#used_qty:=(use_qty - use_qty_detail) as use_qty_detail,
if(remarks='Use',#new_qty_price,0) as use_price,
(#used_qty * new_qty_price) as use_total, 0 as bal_qty, 0 as old_qty,
0 as old_qty_price, 0 as new_qty,0 as new_qty_price,
#bal_qty_detail:=if(remarks='Buy', buy_qty, bal_qty) as bal_qty_detail,
new_qty_price as bal_price,
(#bal_qty_detail * new_qty_price) as bal_total, split_flag
FROM test2)
) as t order by 2

Related

Sum multiple columns in multiple rows

I have following data structure for sales:
id year M01 M02 M03 M04 M05 M06 M07 M08 M09 M10 M11 M12
1 2020 0 5 4 0 10 0 0 0 0 0 0 0
1 2019 4 3 0 0 6 0 7 0 8 0 0 10
2 2020 0 5 4 0 10 0 0 0 0 0 0 0
2 2019 4 3 0 0 6 0 7 0 8 0 0 10
I need to know how many products with id=1 were sold for the last 12 month. If we are in June 2020 I need to sum M01, M02, M03, M04, M05 (WHERE year=2020) and M06, M07, M08, M09, M10, M11, M12 (WHERE year=2019) WHERE id=1. I should get a value of 36.
Please, any suggestions on how to do that in MySQL?
You need to fix your data model. Unpivot and then aggregate:
with reasonable_format as (
select id, year, str_to_date(concat(year, '-01-01'), '%Y-%m-%d') as date, m01 as amount from sales union all
select id, year, str_to_date(concat(year, '-02-01'), '%Y-%m-%d') as date, m02 from sales union all
. . .
select id, year, str_to_date(concat(year, '-02-01'), '%Y-%m-%d') as date, m12 from sales
)
select sum(amount)
from reasonable_format rf
where id = 1 and date <= curdate - interval 1 year;
reasonable_format is what your data should look like.

How to calculate the drawdown in Mysql with Window Functions?

I have this schema:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` int(11) DEFAULT NULL,
`group_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
and i have populated that table with the following data:
insert into test (amount, group_id) values
(1,1), (3,1), (-4,1), (-2,1), (5,1), (10,1), (18,1), (-3,1),
(-5,1), (-7,1), (12,1), (-9,1), (6,1), (0,1), (185,2), (-150,2)
The table is:
# id, amount, group_id
1, 1, 1
2, 3, 1
3, -4, 1
4, -2, 1
5, 5, 1
6, 10, 1
7, 18, 1
8, -3, 1
9, -5, 1
10, -7, 1
11, 12, 1
12, -9, 1
13, 6, 1
14, 0, 1
15, 185, 2
16, -150, 2
This is the query i am using right now:
SELECT
t1.id,
t1.amount,
t1.cumsum,
(MAX(t1.cumsum) OVER (ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - t1.cumsum) as drawdown
FROM
(
SELECT
id,
amount,
group_id,
SUM(amount) OVER (ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumsum
FROM
test
) as t1
order by drawdown desc
the query returns this output:
id, amount, cumsum, drawdown
10 -7 16 15
12 -9 19 12
9 -5 23 8
4 -2 -2 6
14 0 25 6
13 6 25 6
3 -4 0 4
8 -3 28 3
11 12 28 3
5 5 3 1
16 150 360 0
2 3 4 0
7 18 31 0
15 185 210 0
1 1 1 0
6 10 13 0
Just a fast clarification:
With the term "drawdown" (in this case) i mean the difference from the max cumsum of the value(field) AND the simple cumsum (cumulative sum).
I am not referring to any particular trading definition, i just need to difference between the biggest pick and the lowest. (obviously the highest pick must occour before the lowest = downtrend).
OK, my problem is that i need to group by the field group_id, if i add the group by clause on the query all the windows function will mess up.
RESULT EXPECTED:
I need to get a list grouped by group_id field that show the max drawdown for each group.
Edit: (#Akina)
group_id, drawdown
1 15
2 150

Hive/ MySQL - Need help to increment consecutive 1's in the input column

Need help in the below input column, for which I need the expected output column data. I need to increment the output column wherever I have consecutive 1's in the input column.
ID Input_column Expected Output Column date_start date_end
1A 0 0 ts1 ts2
1A 1 0 ts4 ts6
2B 0 0 ts7 ts9
2B 1 1 ... ...
2B 1 1 ... ...
2B 0 0 ... ...
2B 0 0 ... ...
2B 1 2 ... ...
2B 1 2 ts11 ts15
2B 1 2 ts20 ts22
2B 0 0 ... ...
3C 0 0 ... ...
3C 1 3 ... ...
3C 1 3 ... ...
3C 1 3
3C 0 0
3C 1 4
3C 1 4
3C 0 0
3C 0 0 ts50 ts53
3C 1 0 tsxx tsyy
3C 0 0 tsyy tsnn
I tried the below answers, but it didn't worked out as expected.
1) hive how to increment the values specific to condition?
2) Hive query generating identifiers for a sequence of row matching a condition
Could someone help me in resolving this problem?
Pure SQL solution, using windowing functions, no joins, tested on Hive with your data example:
with your_table as --use your table instead of this CTE
(
select stack(23,
1 , 0,
2 , 1,
3 , 0,
4 , 1,
5 , 1,
6 , 0,
7 , 0,
8 , 1,
9 , 1,
10, 1,
11, 0,
12, 0,
13, 1,
14, 1,
15, 1,
16, 1,
17, 0,
18, 1,
19, 1,
20, 0,
21, 0,
22, 1,
23, 0
) as ( ID ,Input_column )
) --use your table instead of this CTE
select s.id, s.input_column,
case when grp_id is null then 0
else dense_rank() over (partition by (grp_id is null) order by grp_id)
end as output_column
from
(
select s.id, s.input_column,
case when same_group_flag then --distribute same grp_id across same group
max(grp_id) over(order by id rows between unbounded preceding and current row )
end as grp_id
from
(
select s.id, s.input_column ,
case when input_column=1 and (prev_value!=1 or prev_value is null) and next_value=1 then id end as grp_id,
input_column=1 and (prev_value=1 or next_value=1) as same_group_flag
from
(
select id, input_column,
lead(input_column) over(order by id) next_value,
lag(input_column) over(order by id) prev_value
from your_table
)s
)s
)s
order by id;
Result:
id input_column output_column
1 0 0
2 1 0
3 0 0
4 1 1
5 1 1
6 0 0
7 0 0
8 1 2
9 1 2
10 1 2
11 0 0
12 0 0
13 1 3
14 1 3
15 1 3
16 1 3
17 0 0
18 1 4
19 1 4
20 0 0
21 0 0
22 1 0
23 0 0
Time taken: 226.407 seconds, Fetched: 23 row(s)
The result is exactly as expected. Also have a look at the very similar question: https://stackoverflow.com/a/55336802/2700344
here is one way to solve this issue but table should have primary key required.
you have to use mysql 8.0 for this
delimiter $$
drop procedure if exists test2 $$
create procedure test2()
begin
declare v_count int default 1 ;
declare v_loop int default 1 ;
declare v_i int;
declare v_j int;
declare v_id int;
declare work cursor for select sr_no,lead(sr_no,1)over(order by id) as sr_no2,id from tmp;
SET #row_number:=0;
SET #db_names:='';
drop temporary table if exists tmp;
create TEMPORARY table tmp as
select id,sr_no from
(select id,
#row_number:= CASE WHEN (value1 and value2 =1) or #db_name=1 THEN 1 ELSE 0 END AS sr_no ,
#db_name:= (CASE WHEN (value1 and value2 =1) THEN 1 ELSE 0 END)
from
(SELECT t2.id, t2.value1 as value2,t1.value1
FROM t4 t1
inner join t4 t2
on (t1.id = t2.id+1))A)d;
OPEN work;
work: LOOP
FETCH work INTO v_i,v_j,v_id;
if ((v_i and v_j = 1) or v_i=1 ) then
SET v_loop=v_loop+1;
if (v_loop > 0)then
update tmp SET sr_no= v_count where id=v_id;
end if;
else
if(v_loop > 1)then
SET v_count=v_count+1;
SET v_loop =0;
else
SET v_loop =0;
end if ;
end if;
END LOOP work;
CLOSE work;
end $$
delimiter $$
run this sp and then just use
select * from tmp for your output

Enter the same value for the entire year

I have table Payments
Client Dt Payment
1 201311 10
1 201312 0
2 201401 0
1 201402 0
1 201403 0
And i want select where i add to this select column "OwnerFlag", where if the client has paid in that year then in all rows for that year for that client will be OwnerFlag 1, otherwise its 0. So the final select should look like :
Client Dt Payment OwnerFlag
1 201311 10 1
1 201312 0 1
2 201401 0 0
1 201402 0 0
1 201403 0 0
Thank you.
Presuming that DT is a datetime column:
SELECT Client, Dt, Payment,
OwnerFlag = CASE WHEN EXISTS
(
SELECT 1 FROM dbo.Payments p1
WHERE p1.ClientID = p.ClientID
AND YEAR(p1.Dt) = YEAR(p.Dt)
AND p1.Pament <> 0
) THEN 1 ELSE 0 END
FROM dbo.Payments p

need help in forming sql query

i have one master table and 2 tables, one is inward table and the other one is issue_return_broken table.
all the 3 tables are related using the ITEM_CODE (primary key)..
if i run the below 3 queries ,
Master query :
select item_code, item_name , item_spec, item_quantity,item_unitprice,item_value from
ven_inv_partmaster
where item_code ='NAVTES13'
Query 1:
select entry_date, quantity_in from ven_inv_inwardmaster
where item_code ='NAVTES13'
group by entry_date,quantity_in
query 2:
select issue_date, issue_qnty,rtn_qnty,brkn_qnty from ven_inv_ibrmaster_log ibrlog
where ibrlog.item_code ='NAVTES13' and issue_dateid !=0
group by issue_date,issue_qnty,rtn_qnty,brkn_qnty
Query 3:
select rtn_date, rtn_qnty,brkn_qnty from ven_inv_ibrmaster_log ibrlog
where ibrlog.item_code ='NAVTES13' and issue_dateid =0
group by rtn_date,rtn_qnty,brkn_qnty
i am getting the output as below,
item_code item_name item_spec item_quantity item_unitprice item_value
NAVTES13 NAVIN TEST13 175 15.00 2175.00
output1:
entry_date quantity_in
2012-04-01 00:00:00.000 50
2012-04-05 00:00:00.000 50
output 2:
issue_date issue_qnty rtn_qnty brkn_qnty
2012-04-02 00:00:00.000 25 0 0
2012-04-10 00:00:00.000 10 0 0
output 3:
rtn_date rtn_qnty brkn_qnty
2012-04-05 00:00:00.000 10 0
2012-04-10 00:00:00.000 9 6
i need to combine all these queries into a single query and need a result set like this..
Date Quantity_Inward Quantity_Issued Return_Quantity Broken_Quantity
1/4/2012 50 0 0 0
2/4/2012 0 25 0 0
5/4/2012 0 0 10 0
5/4/2012 50 0 0 0
10/4/2012 0 0 9 6
10/4/2012 0 10 0 0
please help me out to solve this query..
inward & ibr master table :
To combine the results of your queries in the manner shown, use UNION with ordering in an outer query:
SELECT
DATE_FORMAT(logdate, '%e/%c/%Y') AS `Date`,
quantity_in AS Quantity_Inward,
issue_qnty AS Quantity_Issued,
rtn_qnty AS Return_Quantity,
brkn_qnty AS Broken_Quantity
FROM (
select date(entry_date) as logdate, quantity_in,
0 as issue_qnty, 0 as rtn_qnty, 0 as brkn_qnty
from ven_inv_inwardmaster
where item_code ='NAVTES13'
UNION ALL
select date(issue_date), 0, issue_qnty, rtn_qnty, brkn_qnty
from ven_inv_ibrmaster_log
where item_code ='NAVTES13' and issue_dateid != 0
UNION ALL
select date(rtn_date), 0, 0, rtn_qnty, brkn_qnty
from ven_inv_ibrmaster_log
where item_code ='NAVTES13' and issue_dateid = 0
) AS t
ORDER BY logdate ASC
You could even aggregate in the outer query if so desired (your sample output doesn't do so):
SELECT
DATE_FORMAT(logdate, '%e/%c/%Y') AS `Date`,
SUM(quantity_in) AS Quantity_Inward,
SUM(issue_qnty) AS Quantity_Issued,
SUM(rtn_qnty) AS Return_Quantity,
SUM(brkn_qnty) AS Broken_Quantity
FROM (
...
) AS t
GROUP BY logdate
ORDER BY logdate ASC
You might improve performance slightly by combining your queries 2 and 3 as follows:
select
date(if(issue_dateid = 0, rtn_date, issue_date)),
if(issue_dateid = 0, 0, issue_qnty),
rtn_qnty,
brkn_qnty
from ven_inv_ibrmaster_log
where item_code = 'NAVTES13'
Note I have removed the GROUP BY clauses from your queries as your comment above suggests they are not required.