id | amount
1 | 96
2 | 0.63
3 | 351.03
4 | 736
5 | 53
6 | 39
7 | 105
8 | 91
I want to get the row where sum(amount) reach 1000
please note only the row that trigger 1000
This query should do what (I think) you want:
select id, (select sum(amount)
from table1 t1
where t1.id <= table1.id) as total
from table1
having total >= 1000
limit 1
For your sample table, it gives
id total
4 1183.66
Related
I have created a dataset that has columns for 2 customers:
Cust_No Transaction_date amount credit_debit running_total row_num
1 5/27/2022 800 D -200 1
1 5/26/2022 300 D 600 2
1 5/22/2022 800 C 900 3
1 5/20/2022 100 C 100 4
9 5/16/2022 500 D -300 1
9 5/14/2022 300 D 200 2
9 5/6/2022 200 C 500 3
9 5/5/2022 500 D 300 4
9 5/2/2022 300 D 800 5
9 5/2/2022 500 C 1100 6
9 5/1/2022 500 C 600 7
9 5/1/2022 100 C 100 8
The result I am looking for is:
Cust_No Transaction_date amount credit_debit running_total row_num
1 5/27/2022 800 D -200 1
1 5/26/2022 300 D 600 2
1 5/22/2022 800 C 900 3
9 5/16/2022 500 D -300 1
9 5/14/2022 300 D 200 2
9 5/6/2022 200 C 500 3
9 5/5/2022 500 D 300 4
9 5/2/2022 300 D 800 5
9 5/2/2022 500 C 1100 6
I sorted the dataset based on latest transaction for each customer.
We note the latest transaction amount and search for first occurrence of same amount that was a credit (C) and exclude the rest of the rows after it.
In the example above: Customer 9 has lastest debit transaction of 500, so we look for most recent credit transaction of 500 and exclude all the rows after that for customer 9.
Progress Made so far:
calculated the running total using logic:
sum (case when credit_debit ='C' then amount else -1*amount end) over (partition by cust_no order by transaction_date desc ) as running_total
I also got the data using lead 1,2,3,4,5 but this is not efficient and I could have multiple rows before I find the first credit number with amount same as 1st row:
case when lead(amount, 1) over(partition by cust_no order by transaction_date desc) = amount then amount else null end as lead1
No sure which dbms this is for but it need a lateral join in postgres.
It searches for the most recent transaction identified when rn = 1, then it matches that amount to an earlier credit transaction of the same amount and using the rn of that row to form a boundary of row numbers to be returned:
with CTE as (
select
Cust_No, Transaction_date, amount, credit_debit, running_total
, row_number() over(partition by cust_no order by transaction_date DESC) as rn
from mytable
)
, RANGE as (
select *
from CTE
left join lateral (
select c.rn as ignore_after
from CTE as c
where CTE.Cust_No = c.Cust_No
and CTE.amount = c.amount
and c.credit_debit = 'C'
and CTE.rn = 1
order by c.rn ASC
limit 1
) oa on true
where CTE.rn = 1
)
select
CTE.*
from CTE
inner join RANGE on CTE.rn between RANGE.rn and RANGE.ignore_after
and CTE.cust_no = RANGE.cust_no
Cust_No | Transaction_date | amount | credit_debit | running_total | rn
------: | :--------------- | -----: | :----------- | ------------: | -:
1 | 2022-05-27 | 800 | D | -200 | 1
1 | 2022-05-26 | 300 | D | 600 | 2
1 | 2022-05-22 | 800 | C | 900 | 3
9 | 2022-05-16 | 500 | D | -300 | 1
9 | 2022-05-14 | 300 | D | 200 | 2
9 | 2022-05-06 | 200 | C | 500 | 3
9 | 2022-05-05 | 500 | D | 300 | 4
9 | 2022-05-02 | 300 | D | 800 | 5
9 | 2022-05-02 | 500 | C | 1100 | 6
for postgres see: db<>fiddle here
nb: for an "outer apply" example I have also used SQL Server in the following fiddle see: db<>fiddle here
I have a table of revenue as
title_id revenue cost
1 10 5
2 10 5
3 10 5
4 10 5
1 20 6
2 20 6
3 20 6
4 20 6
when i execute this query
SELECT SUM(revenue),SUM(cost)
FROM revenue
GROUP BY revenue.title_id
it produces result
title_id revenue cost
1 30 11
2 30 11
3 30 11
4 30 11
which is ok, now i want to combine sum result with another table which has structure like this
title_id interest
1 10
2 10
3 10
4 10
1 20
2 20
3 20
4 20
when i execute join with aggregate function like this
SELECT SUM(revenue),SUM(cost),SUM(interest)
FROM revenue
LEFT JOIN fund ON revenue.title_id = fund.title_id
GROUP BY revenue.title_id,fund.title_id
it double the result
title_id revenue cost interest
1 60 22 60
2 60 22 60
3 60 22 60
4 60 22 60
I can't understand why is it double it,please help
Its doubling because you have title repeated in fund and revenue tables. This multiplies the number of records where it matches. This is pretty easy to see if you remove the aggregate functions and look at the raw data. See here
The way to get around this is to create inline views of your aggregates and join on the those results.
SELECT R.title_id,
R.revenue,
R.cost,
F.interest
FROM (SELECT title_id,
Sum(revenue) revenue,
Sum(cost) cost
FROM revenue
GROUP BY revenue.title_id) r
LEFT JOIN (SELECT title_id,
Sum(interest) interest
FROM fund
GROUP BY title_id) f
ON r.title_id = F.title_id
output
| TITLE_ID | REVENUE | COST | INTEREST |
----------------------------------------
| 1 | 30 | 11 | 30 |
| 2 | 30 | 11 | 30 |
| 3 | 30 | 11 | 30 |
| 4 | 30 | 11 | 30 |
demo
The reason for this is that you have joined the table the first derived table from the second table without grouping it. To solve the problem, group the second table (fund) and join it with the first derived table using LEFT JOIN.
SELECT b.title_id,
b.TotalRevenue,
b.TotalCost,
d.TotalInterest
FROM
(
SELECT a.title_id,
SUM(a.revenue) TotalRevenue,
SUM(a.cost) TotalCost
FROM revenue a
GROUP BY a.title_id
) b LEFT JOIN
(
SELECT c.title_id,
SUM(a.interest) TotalInterest
FROM fund c
GROUP BY c.title_id
) d ON b.title_id = d.title_id
There are two rows for each title_id in revenue table.
I have two following tables
table 1)
ID | HOTEL ID | NAME
1 100 xyz
2 101 pqr
3 102 abc
table 2)
ID | BOOKING ID | DEPARTURE DATE | AMOUNT
1 1 2013-04-12 100
2 1 2013-04-14 120
3 1 2013-04-9 90
4 2 2013-04-14 100
5 2 2013-04-18 150
6 3 2013-04-12 100
I want to get reault in mysql such that it take the row from table two with MAX DEPARTURE DATE.
ID | BOOKING ID | DEPARTURE DATE | AMOUNT
2 1 2013-04-14 120
5 2 2013-04-18 150
6 3 2013-04-12 100
SELECT b.ID,
b.BookingID,
a.Name,
b.departureDate,
b.Amount
FROM Table1 a
INNER JOIN Table2 b
ON a.ID = b.BookingID
INNER JOIN
(
SELECT BookingID, MAX(DepartureDate) Max_Date
FROM Table2
GROUP BY BookingID
) c ON b.BookingID = c.BookingID AND
b.DepartureDate = c.Max_date
SQLFiddle Demo
Well,
SELECT * FROM `table2` ORDER BY `DEPARTURE_DATE` DESC LIMIT 0,1
should help
I have a table of revenue as
title_id revenue cost
1 10 5
2 10 5
3 10 5
4 10 5
1 20 6
2 20 6
3 20 6
4 20 6
when i execute this query
SELECT SUM(revenue),SUM(cost)
FROM revenue
GROUP BY revenue.title_id
it produces result
title_id revenue cost
1 30 11
2 30 11
3 30 11
4 30 11
which is ok, now i want to combine sum result with another table which has structure like this
title_id interest
1 10
2 10
3 10
4 10
1 20
2 20
3 20
4 20
when i execute join with aggregate function like this
SELECT SUM(revenue),SUM(cost),SUM(interest)
FROM revenue
LEFT JOIN fund ON revenue.title_id = fund.title_id
GROUP BY revenue.title_id,fund.title_id
it double the result
title_id revenue cost interest
1 60 22 60
2 60 22 60
3 60 22 60
4 60 22 60
I can't understand why is it double it,please help
Its doubling because you have title repeated in fund and revenue tables. This multiplies the number of records where it matches. This is pretty easy to see if you remove the aggregate functions and look at the raw data. See here
The way to get around this is to create inline views of your aggregates and join on the those results.
SELECT R.title_id,
R.revenue,
R.cost,
F.interest
FROM (SELECT title_id,
Sum(revenue) revenue,
Sum(cost) cost
FROM revenue
GROUP BY revenue.title_id) r
LEFT JOIN (SELECT title_id,
Sum(interest) interest
FROM fund
GROUP BY title_id) f
ON r.title_id = F.title_id
output
| TITLE_ID | REVENUE | COST | INTEREST |
----------------------------------------
| 1 | 30 | 11 | 30 |
| 2 | 30 | 11 | 30 |
| 3 | 30 | 11 | 30 |
| 4 | 30 | 11 | 30 |
demo
The reason for this is that you have joined the table the first derived table from the second table without grouping it. To solve the problem, group the second table (fund) and join it with the first derived table using LEFT JOIN.
SELECT b.title_id,
b.TotalRevenue,
b.TotalCost,
d.TotalInterest
FROM
(
SELECT a.title_id,
SUM(a.revenue) TotalRevenue,
SUM(a.cost) TotalCost
FROM revenue a
GROUP BY a.title_id
) b LEFT JOIN
(
SELECT c.title_id,
SUM(a.interest) TotalInterest
FROM fund c
GROUP BY c.title_id
) d ON b.title_id = d.title_id
There are two rows for each title_id in revenue table.
Let's say that we have a table with COLUMN1 and COLUMN 2. Here's a sample of the records:
COLUMN 1 | COLUMN 2
124 | 12
124 | 11
124 | 10
124 | 9
26 | 8
65 | 7
65 | 6
65 | 5
65 | 4
23 | 3
124 | 2
124 | 1
124 | 0
There is absolutely no pattern to this, but what I'd like to do is get:
COUNT(*) | COLUMN 1 | Smallest Column 2
4 | 124 | 9
1 | 26 | 8
4 | 65 | 4
1 | 23 | 3
3 | 124 | 0
So far, I've been doing this with PHP, but I'd like to find a way to do this in MySQL, as I'm sure it'd be a lot more efficient. The problem is, I can't even think of where to start with this. A regular GROUP BY COLUMN 1 wouldn't work because I want two results for 124, since it appears in two different instances. I've been fiddling around for hours and looking into the documentation and Google, but I haven't been able to find anything yet, and I was wondering if any of you would be able to point me in the right direction. Is this even possible with MySQL?
Well, it took a bit of fiddling, but here it is!
This assumes you have an id column in your table that you order by to get a consistent ordering (if you don't have an id column, order by timestamp or whatever in the inner query).
set #prev := '', #low := 0, #cnt := 0, #grp :=0;
select cnt, column1, low
from (
select
column2,
#low := if(#prev = column1, least(column2, #low), column2) low,
#cnt := if(#prev = column1, #cnt + 1, 1) cnt,
#grp := if(#prev = column1, #grp, #grp + 1) grp,
#prev := column1 column1
from (select column1, column2 from so9091342 order by id) x
order by grp, cnt desc) y
group by grp;
Here's the sql needed to set up a table for testing:
create table so9091342 (id int primary key auto_increment, column1 int, column2 int);
insert into so9091342 (column1, column2) values (124,12),(124,11),(124,10),(124,9),(26,8),(65,7),(65,6),(65,5),(65,4),(23,3),(124,2),(124,1),(124,0);
Output of above query:
+------+---------+------+
| cnt | column1 | low |
+------+---------+------+
| 4 | 124 | 9 |
| 1 | 26 | 8 |
| 4 | 65 | 4 |
| 1 | 23 | 3 |
| 3 | 124 | 0 |
+------+---------+------+
p.s. I named the table so9091342 because this is SO question ID #9091342.
Interesting question. I know Oracle much better than MySQL so I was able to get it working in Oracle. Might be a better way but this is what I came up with.
select count(col1) as cnt, col1, min(col2) as smallestCol2
from (
select col1, col2, col2-rnk as rnk
from
(
select col1, col2, RANK() OVER (PARTITION by col1 order by col2 asc) as rnk
from tmp_tbl
)
)
group by col1,rnk
order by min(col2) desc
I'm not quite sure how rank and partition work in MySQL but this might be helpful:
Rank function in MySQL
EDIT: To clarify what is going on in my query:
The inner query assigns a unique counter (RNK) to each value in column 1. The result of the most inner query is:
COL1 COL2 RNK
23 3 1
26 8 1
65 4 1
65 5 2
65 6 3
65 7 4
124 0 1
124 1 2
124 2 3
124 9 4
124 10 5
124 11 6
124 12 7
By subtracting the rank from column 2, you can get a unique value for each grouping of column 1 values. The result of the second nested query is:
COL1 COL2 RNK
23 3 2
26 8 7
65 4 3
65 5 3
65 6 3
65 7 3
124 0 -1
124 1 -1
124 2 -1
124 9 5
124 10 5
124 11 5
124 12 5
Then you can group on column 1 and that unique value. The final result:
CNT COL1 SMALLESTCOL2
4 124 9
1 26 8
4 65 4
1 23 3
3 124 0