Mysql query to find a value in a range of cumulative sum - mysql

I have a table that looks like this:
id
count
1
100
2
50
3
10
4
10
I want to run select * query ,by using a new column called cumulative_sum , such that this new column is not create to the table rather is being queried (calculated) every time and use to select rows lying between limit and offset, + 1 more row after it.
Suppose I provide offset =130 and limit= 25 (i.e. range 130 to 155) then it should return row 2 row3 and row 4 (ie. last row + 1)
id
count
cumulative_sum
1
100
100
2
50
150
3
10
160
4
10
170
How to write a Mysql query for the above condition?
I trying to achieve this for quite some time now please help me to understand how to do this?
Cummulative sum column is just sum of = last rows cummulative sum + count of present row

On MySQL 8+, we can simply use SUM() as an analytic function:
SELECT id, count, SUM(count) OVER (ORDER BY id) AS cumulative_sum
FROM yourTable
ORDER BY id;
On earlier versions of MySQL, we can use a correlated subquery to find the rolling sum:
SELECT id, count,
(SELECT SUM(t2.count) FROM yourTable t2
WHERE t2.id <= t1.id) AS cumulative_sum
FROM yourTable t1
ORDER BY id;

Use Window function to achieve this (works with MySQL 8.0 and above):
SELECT id, count, sum(count) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cummulative_sum
FROM your_table
ORDER BY id

Related

SQL - How to select random rows until the total value of the row is a certain number?

I currently have a table which has a column which holds time as an integer value. How do I select all the rows in my table in a random order until the total value of the time = a certain number e.g 10.
Something like this would work for SQL Server:
select id, timeValue from (
select id,
timeValue,
SUM(timeValue) OVER (ORDER BY CHECKSUM(NewId())) as total
from myTable) as subq
where total < 10
In MySQL, you would use the following for the first row that meets or exceeds 10:
select id, timeValue from (
from (select t.*
sum(timeValue) over (order by rand()) as running_sum
from t
) t
where (running_sum - timeValue) < 10;
If you want rows up to but not exceeding 10, then:
where running_sum <= 10

Using SUM for first n rows in each group in SQL

I have one table with two columns (client_id and spent). Each client bought something more than 20 times. I want to sum spendings for each client.
I know that I can use sum and group by to do that, but I want to use sum not for all values in the groups but for only first 10 values. How can I do that?
I have tried with top 10 and limit 10, but It does not work.
I have 10 different clients and more than 200 rows. Clients are not scattered, they are in order, so I have 20 rows on client1 than 20 rows of on client2... Each client appears more than 20 times. I want to use sum and group by, but I do not want to sum all values (more than 20 for each row) , i want to sum first 10 values. Its ordered by time for each client
select client_id, sum(spendings)
from my_table
group by client_id
If you are using Mysql 8.0, You can do this by using window function.
select client_id, sum(spendings)
from (select client_id, spendings, row_number() over (partition by client_id order by <timecol>) rn
from my_table) t
where rn < 11
group by client_id
For MySQL, try this following code-
SELECT client_id,SUM(spendings)
FROM
(
select client_id,
spendings,
#row_num :=IF(client_id = #client_id,#row_num+1,1)AS RowNumber,
#client_id := client_id
FROM my_table
ORDER BY client_id
-- You may need to add here appropriate ordering
-- To get your desired 10 rows for group by in the result
)A
WHERE A.RowNumber < 11
GROUP BY client_id

MySQL AVG ... LIMIT returns total AVG

Table :
a | b
1 | 15
2 | 10
3 | 20
4 | 30
Query:
SELECT AVG(table.b) FROM table ORDER BY table.a ASC LIMIT 3
Will return 18.75 instead of expected 15.
How can I change the query to get my expected result (AVG value for a limited amount of rows)?
You need to use subquery:
SELECT AVG(b)
FROM (SELECT b
FROM table
ORDER BY table.a ASC
LIMIT 3) sub
EDIT:
Without subquery the order of execution is like:
FROM
AVG (AVG is calculated using all values)
ORDER BY (but there is only one value)
LIMIT (LIMIT 3 on one value do nothing)
With subquery the order of execution is like:
FROM
ORDER BY
LIMIT (only 3 values)
outer query AVG (average is calculated using only 3 values)
More info: Logical query processing (TOP/OFFSET FETCH is the same as LIMIT).
Try this instead:
SELECT AVG(A.b) FROM
(SELECT `table`.b FROM `table` ORDER BY `table`.a ASC LIMIT 3) A;
DEMO

in sql, how to make a rank column based on the value of another column?

say I wish to create a table like following:
user score rank
a 100 2
b 200 1
c 50 3
d 50 3
How exactly do I create a rank column in which it updates with the new entry of record with score?
For a small table, the easiest way is a correlated subquery:
select t.*,
(select 1 + count(*)
from t t2
where t2.score > t.score
) as rank
from t
order by score desc;
Note: this implements "rank" as per the rank() window function available in most databases.

select sum where sum

I want to select some entries based on a max+sum condition.
mytable
----------
id | col1 | col2
I want to select all entries that have the sum of col1 & col2 greater than or equal to the max of sum minus X. (don't ask me why :) )
So far I managed to get the sum OK (hereafter aliased as "total") with:
SELECT id,SUM(col1 + col2) AS total FROM mytable GROUP BY id;
I also managed to get the MAX of the sum OK (with a ORDER BY/LIMIT workaround though):
SELECT id,SUM(col + col) as total FROM mytable GROUP BY id ORDER BY total DESC LIMIT 1;
However everytime I try to re-use my alias as a condition (e.g. WHERE total >= ...) I get an "Unknown column" error
Anything would be greatly appreciated
You have some misconceptions about SUM. SUM is an aggregating function, means it works on many records and not just one.
To calculate the sum of two fields per record, you should use only the + operator.
SELECT id, col1+col2 AS 'total'
FROM T1
WHERE
(col1+col2+x) >=(SELECT MAX(col1+col2) from T1)
If you are using group by, you'll need to use a having clause:
SELECT id,SUM(col1+col2) as total FROM mytable GROUP BY id ORDER BY total HAVING total >= x