How to display rows in table but skip multiple rows selection using MYSQL database - mysql
i have one table like this :
Balance Table
id
date
item
desc
debit
credit
1
2021-07-01
june's balance
50
2
2021-07-01
Apple
sell
10
3
2021-07-01
Lemon
buy
10
4
2021-07-05
Strawberry
sell
75
5
2021-07-05
Strawberry
sell
25
6
2021-07-12
Blueberry
buy
10
7
2021-08-01
july's Balance
140
8
2021-08-01
Apple
sell
25
9
2021-08-02
Strawberry
buy
5
10
2021-08-08
Lemon
sell
25
11
2021-08-27
Lemon
sell
35
12
2021-08-30
Blueberry
buy
20
13
2021-09-01
aug's Balance
200
14
2021-09-01
Lemon
sell
20
15
2021-09-07
Blueberry
sell
20
16
2021-09-07
Strawberry
sell
20
17
2021-09-20
Lemon
sell
20
18
2021-09-20
Blueberry
sell
20
then I added a balance column for the monthly data with query like this :
select t.date, t.item, t.desc, t.debit, t.credit,
(#s := #s + t.debit - t.credit) as balance
from balance t cross join
(select #s := 0) p where MONTH(t.date) = 7 //for july
order by t.date
and the result is as follows :
July results
date
item
desc
debit
credit
balance
2021-07-01
June's Balance
50
50
2021-07-01
apple
sell
10
60
2021-07-01
lemon
buy
10
50
2021-07-05
strawberry
sell
75
125
2021-07-06
strawberry
sell
25
150
2021-07-12
blueberry
buy
10
140
August results
date
item
desc
debit
credit
balance
2021-08-01
July's Balance
140
140
2021-08-01
apple
sell
25
165
2021-08-02
strawberry
buy
5
160
2021-08-08
lemon
sell
25
185
2021-08-27
lemon
sell
35
220
2021-08-30
blueberry
buy
20
200
and September results
date
item
desc
debit
credit
balance
2021-09-01
Aug's Balance
200
200
2021-09-01
lemon
sell
20
220
2021-09-07
blueberry
sell
20
240
2021-09-07
strawberry
sell
20
260
2021-09-20
lemon
sell
20
280
2021-09-20
blueberry
sell
20
300
the question is, how to get a table like below, where the desc row used is only June's Balance without July's Balance and Aug's Balance.. thanks for the help
date
item
desc
debit
credit
balance
2021-07-01
June's Balance
50
50
2021-07-01
apple
sell
10
60
2021-07-01
lemon
buy
10
50
2021-07-05
strawberry
sell
75
125
2021-07-06
strawberry
sell
25
150
2021-07-12
blueberry
buy
10
140
2021-08-01
apple
sell
25
165
2021-08-02
strawberry
buy
5
160
2021-08-08
lemon
sell
25
185
2021-08-27
lemon
sell
35
220
2021-08-30
blueberry
buy
20
200
2021-09-01
lemon
sell
20
220
2021-09-07
blueberry
sell
20
240
2021-09-07
strawberry
sell
20
260
2021-09-20
lemon
sell
20
280
2021-09-20
blueberry
sell
20
300
I partially loaded up a table in db-fiddle.com.
This will display the running balances with whatever starting month you choose ('2021-07-01' in this case):
select t.date,
ifnull(t.item, '') as item,
t.desc,
ifnull(t.debit, 0) as debit,
ifnull(t.credit, 0) as credit,
(#s := #s + ifnull(t.debit, 0) - ifnull(t.credit, 0)) as balance
from balance t cross join (select #s := 0) p
where t.date >= '2021-07-01' and (t.date = '2021-07-01' or t.item is not null)
order by t.date
date
desc
item
debit
credit
balance
2021-07-01
june's balance
50
0
50
2021-07-01
sell
Apple
10
0
60
2021-07-01
buy
Lemon
0
10
50
2021-07-05
sell
Strawberry
75
0
125
2021-08-01
sell
Apple
25
0
150
2021-08-02
buy
Strawberry
0
5
145
2021-08-08
sell
Lemon
25
0
170
You could adapt your where clause to exclude all Balances that aren't in the start date.
But your concept doesn't include years, which you must include, when the considered time line goes over a year
select t.`date`, t.item, t.desc, t.debit, t.credit,
(#s := IFNULL(#s,0) + IFNULL(t.debit,0) - IFNULL(t.credit,0)) as balance
from balance t cross join
(select #s := 0) p
where (`desc` LIKE '% Balance' AND MONTH(t.date) = (SELECT MIN(MONTH(`date`)) FROM balance)) or `desc` NOT LIKE '% Balance'
order by t.`date`
date | item | desc | debit | credit | balance
:--------- | :--------- | :------------- | :---- | :----- | ------:
2021-07-01 | null | june's balance | 50 | null | 50
2021-07-01 | Apple | sell | 10 | null | 60
2021-07-01 | Lemon | buy | null | 10 | 50
2021-07-05 | Strawberry | sell | 75 | null | 125
2021-07-05 | Strawberry | sell | 25 | null | 150
2021-07-12 | Blueberry | buy | null | 10 | 140
2021-08-01 | Apple | sell | 25 | null | 165
2021-08-02 | Strawberry | buy | null | 5 | 160
2021-08-08 | Lemon | sell | 25 | null | 185
2021-08-27 | Lemon | sell | 35 | null | 220
2021-08-30 | Blueberry | buy | null | 20 | 200
2021-09-01 | Lemon | sell | 20 | null | 220
2021-09-07 | Blueberry | sell | 20 | null | 240
2021-09-07 | Strawberry | sell | 20 | null | 260
2021-09-20 | Lemon | sell | 20 | null | 280
2021-09-20 | Blueberry | sell | 20 | null | 300
db<>fiddle here
Related
how to perform delete in mysql table using avg() of another table?
table_a user_id score 1 0.33 2 0.34 3 0.35 11 0.90 88 0.80 7 0.10 8 0.11 10 0.09 12 0.80 17 0.80 18 0.80 19 0.80 20 0.80 table_b user_id canon_id 1 1000 2 1000 3 1000 11 4344 88 4344 7 2023 8 2023 10 2023 12 3333 17 3333 18 3333 19 3333 20 3333 In the above case, how can I delete records from table_b where associated table_a.user_ids from table_b.canon_id have avg(score) < 0.50. In this case, canon_id 2023 and associated user_ids 7,8,10 avg(score) is 0.10 hence it should get deleted.
Join table_b to a query that returns all the canon_ids with associated with average < 0.5: delete b from table_b b inner join ( select b.canon_id from table_b b inner join table_a a on a.user_id = b.user_id group by b.canon_id having avg(a.score) < 0.5 ) t on t.canon_id = b.canon_id; See the demo. Results: | user_id | canon_id | | ------- | -------- | | 11 | 4344 | | 88 | 4344 | | 12 | 3333 | | 17 | 3333 | | 18 | 3333 | | 19 | 3333 | | 20 | 3333 |
get the data for last month if next month no data is there
I want to get the data of last month if no data is there in the next month. suppose data is: stock_item month stock pepsi 4 100 pepsi 5 120 pepsi 9 80 coca cola 4 90 coca cola 6 100 coca cola 8 120 the output should be like: stock_item month stock pepsi 4 100 pepsi 5 120 pepsi 6 120 pepsi 7 120 pepsi 8 120 pepsi 9 80 pepsi 10 80 coca cola 4 90 coca cola 5 90 coca cola 6 100 coca cola 7 100 coca cola 8 120 coca cola 9 120 coca cola 10 120 Month is between 4 and 10 because indian fiscal year starts in April and current month is October, so 10.
Here's a partial answer for how to accomplish this for a single stock. First, create a table for the months you want and populate it. This gives us something to iterate over. create table stock_months ( int month_num not null ); insert into stock_months values (4), (5), (6), (7), (8), (9), (10); Now we can select months from this table and left outer join with stocks to get all months. select stock_item, month_num, stock from stock_months sm left outer join stocks s on sm.month_num = s.month and s.stock_item = 'pepsi' +------------+-----------+-------+ | stock_item | month_num | stock | +------------+-----------+-------+ | pepsi | 4 | 100 | | pepsi | 5 | 120 | | pepsi | 9 | 80 | | NULL | 6 | NULL | | NULL | 7 | NULL | | NULL | 8 | NULL | | NULL | 10 | NULL | +------------+-----------+-------+ We can use variables to remember the values of the previous row. select case when stock_item is null then #stock_item else #stock_item := stock_item end as stock_item, month_num, case when stock is null then #stock else #stock := stock end as stock from stock_months sm left outer join stocks s on sm.month_num = s.month and s.stock_item = 'pepsi' order by month_num; +------------+-----------+-------+ | stock_item | month_num | stock | +------------+-----------+-------+ | pepsi | 4 | 100 | | pepsi | 5 | 120 | | pepsi | 6 | 80 | | pepsi | 7 | 80 | | pepsi | 8 | 80 | | pepsi | 9 | 80 | | pepsi | 10 | 80 | +------------+-----------+-------+ Why didn't that work? Because the select iterates through the results of the join in whatever order it likes. Then it sorts. In this case it did the rows with stock_item first. We need to sort the joined rows first. We can do that by selecting from a subselect which is already in order. select case when stock_item is null then #stock_item else #stock_item := stock_item end as stock_item, month_num, case when stock is null then #stock else #stock := stock end as stock from ( select stock_item, month_num, stock from stock_months sm left outer join stocks s on sm.month_num = s.month and s.stock_item = 'pepsi' order by month_num ) stocks; +------------+-----------+-------+ | stock_item | month_num | stock | +------------+-----------+-------+ | pepsi | 4 | 100 | | pepsi | 5 | 120 | | pepsi | 6 | 120 | | pepsi | 7 | 120 | | pepsi | 8 | 120 | | pepsi | 9 | 80 | | pepsi | 10 | 80 | +------------+-----------+-------+ I'm not sure how to go from here to all stock items.
mysql grouped ranking with ties
so i have data in a table like this: id total group_id 1897 738 1 2489 716 2 2325 715 3 1788 702 2 1707 699 3 2400 688 3 2668 682 2 1373 666 1 1494 666 1 1564 660 1 2699 659 1 1307 648 4 1720 645 4 2176 644 1 1454 644 4 2385 639 3 1001 634 2 2099 634 4 1006 632 1 2587 630 3 1955 624 3 1827 624 4 2505 623 4 2062 621 3 1003 618 1 2286 615 4 2722 609 4 how can i rank the ids per group based on the total and giving the same rank when there is a tie? i have tried this solution below but it doesnt take care of the ties. SELECT g1.admission_no , g1.total , g1.stream_id , COUNT(*) AS rn FROM ranktest AS g1 JOIN ranktest AS g2 ON (g2.total, g2.admission_no) >= (g1.total, g1.admission_no) AND g1.stream_id = g2.stream_id GROUP BY g1.admission_no , g1.stream_id , g1.total ORDER BY g1.stream_id , total ; expected id total group_id rank 1897 738 1 1 2489 716 2 1 2325 715 3 1 1788 702 2 2 1707 699 3 2 2400 688 3 3 2668 682 2 3 1373 666 1 2 1494 666 1 2 1564 660 1 3 2699 659 1 4 1307 648 4 1 1720 645 4 2 2176 644 1 4 1454 644 4 3 2385 639 3 4 1001 634 2 4 2099 634 4 4 1006 632 1 5 2587 630 3 5 1955 624 3 6 1827 624 4 5 2505 623 4 6 2062 621 3 6 1003 618 1 6 2286 615 4 7 2722 609 4 8
If original order is not very important you can start from: http://sqlfiddle.com/#!9/a15a2/10 SELECT ranktest.*, IF(#rank IS NULL,#rank:=1, IF(#prev!=group_id,#rank:=1,#rank:=#rank+1) ) rank, #prev:=group_id FROM ranktest ORDER BY group_id, total but keep in mind that this is not very efficient query from performance perspective.
From the MySQL Manual Page entitled User-Defined Variables: In the following statement, you might think that MySQL will evaluate #a first and then do an assignment second: SELECT #a, #a:=#a+1, ...; However, the order of evaluation for expressions involving user variables is undefined. This is why so few people write these answers correctly and safely. The object is not to hit the desired results once, but to do so again and again in real-world environments using best practices and guaranteed results. If you don't read the Obligatory Doc, and implement it, your results are not guaranteed. There is no lazy way to do this and one shouldn't even bother :p select id,total,group_id,rank from ( select id,total,group_id, #rn:=if( group_id!=#curr_grp, greatest(#grp_rank:=1,0), if(total=#prev_grp_total,#grp_rank,greatest(#grp_rank:=#grp_rank+1,0) ) ) as rank, #curr_grp:=group_id, #prev_grp_total:=total from trans01 cross join (select #grp_rank:=0,#curr_grp:=0,#prev_grp_total:=-1) xParams order by group_id,total desc )xDerived; +------+-------+----------+------+ | id | total | group_id | rank | +------+-------+----------+------+ | 1897 | 738 | 1 | 1 | | 1373 | 666 | 1 | 2 | | 1494 | 666 | 1 | 2 | | 1564 | 660 | 1 | 3 | | 2699 | 659 | 1 | 4 | | 2176 | 644 | 1 | 5 | | 1006 | 632 | 1 | 6 | | 1003 | 618 | 1 | 7 | | 2489 | 716 | 2 | 1 | | 1788 | 702 | 2 | 2 | | 2668 | 682 | 2 | 3 | | 1001 | 634 | 2 | 4 | | 2325 | 715 | 3 | 1 | | 1707 | 699 | 3 | 2 | | 2400 | 688 | 3 | 3 | | 2385 | 639 | 3 | 4 | | 2587 | 630 | 3 | 5 | | 1955 | 624 | 3 | 6 | | 2062 | 621 | 3 | 7 | | 1307 | 648 | 4 | 1 | | 1720 | 645 | 4 | 2 | | 1454 | 644 | 4 | 3 | | 2099 | 634 | 4 | 4 | | 1827 | 624 | 4 | 5 | | 2505 | 623 | 4 | 6 | | 2286 | 615 | 4 | 7 | | 2722 | 609 | 4 | 8 | +------+-------+----------+------+
came up with this answer after googling a bit..not sure is its the best but it works for my case: SELECT id, group_id, total, #std:=CASE WHEN #grp <> group_id THEN concat(left(#grp:=group_id, 0), 1) ELSE if(#prev=total,#std,#std+1) END AS rn,#prev:=total FROM (SELECT #std:= -1) s, (SELECT #grp:= -1,#prev:=null) c, (SELECT * FROM table ORDER BY group_id, total desc ) s
Pivot table query in mysql
Is there a way to do a query in mysql with this scenario. i have a table group_name | cost_period | books_cost | others_cost group_A | 1/01/2015 | 100 | 200 group_A | 1/02/2015 | 56 | 86 group_A | 1/01/2015 | 22 | 222 group_A | 1/03/2015 | 30 | 40 group_B | 1/02/2015 | 50 | 10 group_B | 1/02/2015 | 45 | 10 group_B | 1/01/2015 | 22 | 15 group_C | 1/02/2015 | 45 | 20 and i want it to have this format after the query JAN-2015 FEB-2015 MAR_2015 total group_A sum of book cost 122 56 30 208 sum of others cost 422 86 40 548 group_B sum of book cost 22 95 0 117 sum of others cost 15 20 0 45 group_C sum of book cost 0 45 0 45 sum of others cost 0 20 0 20 is there a way this is possible by a query to avoid using a pivot tool once data is gathered? since jasper's crosstabs are not that flexible thanks
Dynamic Cross Tab in MySQL
I have the following table with the following data Year | Age Group | Male | Female 2000 | 0 - 25 | 50 | 100 2000 | 26 above | 40 | 75 2001 | 0 - 25 | 150 | 86 2001 | 26 above | 65 | 83 I would like to create a cross tab in the following format | Male | Female 2000 | 90 | 175 0 - 25 | 50 | 100 26 above | 40 | 75 2001 | 215 | 169 0 - 25 | 150 | 86 26 above | 65 | 83 I will be very grateful for your assistance.
SQLFiddle example: select * from ( select year,ageGroup,male,female from t union all select year,'' ageGroup,sum(male) male,sum(female) female from t group by year ) st order by year,agegroup