Get single values and sum of all the output in mysql - mysql

SELECT value FROM table produces this result:
1
5
8
3
But I want to get the single values and the sum of all the output
1 17
5 17
8 17
3 17
SELECT value,SUM(value) FROM table produces just only
1 17
How can I somehow "ungroup" my results?
Thanks for your answers.....

Use a sub-query:
SELECT value, (SELECT SUM(value) FROM table) AS sValue
FROM table
You can alternatively use a CROSS JOIN:
SELECT value, sValue
FROM mytable
CROSS JOIN (SELECT SUM(value) AS sValue FROM mytable) AS t

If you don't need the SUM on every row you could use user variables:
SELECT value, #sum := #sum + value AS cumulative
FROM table1
JOIN (SELECT #sum := 0) init
WHERE ...
This will give you a cumulative sum and the last row will have the correct total.
Alternatively, assuming this is part of an application and you are looping through the results to display them, it may be easier to perform the calculation in the application logic.

Related

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

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

Select minimal count of rows with total sum greater than or equal to a given threshold

I have an sql table trade with following data
id| value | price
1| 0.1 |1
2| 0.5 |2
3| 0.9 |2
4| 0.3 |2
How do I make an SQL query so that I get the count of entries limited to total value of 0.9 for price 2 ascending by id . For example:-
Select Count of id FROM trade WHERE sum(value) <= 0.9 and price = '2'
Result should come as
3
As there are total 3 entries with id 2,3,4 with values 0.5,0.9,0.3 with price 2 . The sum of them is 1.7 which is more than 0.9 but if we take 0.5 and 0.3 it combines to 0.8 which is lesser than 0.9 . So result should be 3 as it consists value of atleast 0.9 with price 2.
Also is there way to get the id of the results with last and first highest value in order.
So it looks like :-
4
2
3
Help appreciated :)
select id from
(select id, if(not(#sum > 0.9), 1, 0) mark, (#sum:=#sum+value) as sum
from trade cross join (select #sum:=0) s
where price=2 order by value asc) t
where mark =1
The inner query counts cumulative sum and addional field mark, which is equal one while sum is less and turn into zero when it is over 0.9. Since it's working one step later, it gathers the first row where sum is above the limit.
The result of the inner select
id mark sum
4 1 0.30000001192092896
2 1 0.800000011920929
3 1 1.699999988079071
Now in the outer query you just need to select rows with mark equal 1. And it results in 4,2,3
demo on sqlfiddle
You can achieve this by using a temporary SQL variable which stores partial sums and used rows count. Note that there are two SQL statements:
SET #tempsum := 0, #rowscount := 0;
SELECT MIN(tempcount) FROM
(SELECT
(#rowscount := #rowscount + 1) AS tempcount,
(#tempsum := #tempsum + value) AS tempsum
FROM trade WHERE
price='2'
ORDER BY value
) AS partialsums
WHERE tempsum>=0.9;
This way the partial sums are built only once. Without variables, you would need to build another subquery which builds multiple partial sums.
Here the SQL Fiddle: http://sqlfiddle.com/#!9/38fc2/11/1
See also: Create a Cumulative Sum Column in MySQL
You may also use variables to store the IDs involved, i.e.:
SET #tempsum := 0, #rowscount := 0, #ids := '';
SELECT MIN(tempcount), tempids FROM
(SELECT
(#tempsum := #tempsum + value) AS tempsum,
(#rowscount := #rowscount + 1) AS tempcount,
(#ids := concat(#ids, ' ', id)) AS tempids
FROM trade WHERE
price='2'
ORDER BY value
) AS partialsums
WHERE tempsum>=0.9;
See Fiddle: http://sqlfiddle.com/#!9/38fc2/33/0
If you need the count of the distinct ID values you could use count(distinct id)
and do the fact you checking for an aggregated result (sum() ..) you should use having and not where
Select Count(distinct id )
FROM trade
where price = 2
HAVING sum(value) <= 0.9
if you want the count for the rows with ID not null theb you could use count(id)
Select Count(id )
FROM trade
where price = 2
HAVING sum(value) <= 0.9
NB you are using price as a string

One MySQL query to get AVG by different Groupings?

Wondering is there is a way to write the following in ONE MySQL query.
I have a table:
cust_ID | rpt_name | req_secs
In the query I'd like to get:
the AVG req_secs when grouped by cust_ID
the AVG req_secs when grouped by rpt_name
the total req_secs AVG
I know I can do separate grouping queries on the same table then UNION the results into one. But I was hoping there was some way to do it in one query.
Thanks.
Well, the following would does two out of three:
select n,
(case when n = 1 then cast(cust_id as varchar(255)) else rpt_name end) as grouping,
avg(req_secs)
from t cross join
(select 1 as n union all select 2
) n
group by n, (case when n = 1 then cust_id else rpt_name end);
This essentially "doubles" the data and then does the aggregation for each group. This assumes that cust_id and rpt_name are of compatible types. (The query could be tweaked if this is not the case.)
Actually, you can get the overall average by using rollup:
select n,
(case when n = 1 then cust_id else rpt_name end) as grouping,
avg(req_secs)
from t cross join
(select 1 as n union all select 2
) n
group by n, (case when n = 1 then cast(cust_id as varchar(255)) else rpt_name end) with rollup
This works for average because the average is the same on the "doubled" data as for the original data. It wouldn't work for sum() or count().
No there is not. You can group by a combination of cust_ID and rpt_name at the same time (i.e. two levels of grouping) but you are not going to be able to do separate top-level groupings and then a non-grouped aggregation at the same time.
Because of the way GROUP BY works, the SQL to do this is a little tricky. One way to get the result is to get three copies of the rows, and group each set of rows separately.
SELECT g.gkey
, IF(g.grp='cust_id',t.cust_ID,IF(g.grp='rpt_name',t.rpt_name,'')) AS gval
, AVG(t.req_secs) AS avg_req_secs
FROM (SELECT 'cust_id' AS gkey UNION ALL SELECT 'rpt_name' UNION ALL SELECT 'total') g
CROSS
JOIN mytable t
GROUP
BY g.gkey
, IF(g.grp='cust_id',t.cust_ID,IF(g.grp='rpt_name',t.rpt_name,''))
The inline view aliased as "g" doesn't have to use UNION ALL operators, you just need a rowset that returns exactly 3 rows with distinct values. I just used the UNION ALL as a convenient way to return three literal values as a rowset, so I could join that to the original table.

how to get the sum of the rows before the current row in MYSQL? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
MySQL query that computes partial sums
ok, the question is not clear at all so the example would be:
i have a table like this:
id amount
1 1000
2 2500
3 5000
and i need to select from it the following data:
id oamount total
1 1000 1000
2 2500 3500
3 5000 8500
i tried this but it is not correct:
select *,sum(oamount) from `table`
group by id;
and i can't figure it out
I've answered a very similar where they were trying to get cash flow balances for beginning / ending of each day... Found here
Yours would be very similar... Prequery the data in the final order you want it (ie: starting ID would be the first of the result set), then apply what you want with MySQL Variables
select
PreAgg.ID,
PreAgg.Amount,
#PrevBal := #PrevBal + PreAgg.Amount as Total
from
( select
YT.id,
YT.amount
from
YourTable YT
order by
YT.id ) as PreAgg,
( select #PrevBal := 0.00 ) as SqlVars
I've actually kept the pre-aggregate as a query... in case you wanted to actually DO some aggregations like based on transactions on a daily basis, or applied some other WHERE clause. This would allow flexibility to ensure your final output order was prepared BEFORE starting your #PrevBal accumulation.
Try the following:
select
*,
(select sum(oamount) from `table` WHERE id <= t.Id) AS total
from `table` AS t
SELECT id,amount,#total := #total + amount
FROM `table`, (SELECT #total := 0) as dummy
ORDER BY id;
Note that this doesn't work when using GROUP BY clauses / aggregates.
try this:
SET #res:=0;
SELECT
t.a,
t.b,
(#res := #res + t.b) AS summ
FROM
(SELECT first AS a, second AS b FROM table GROUP BY a ORDER BY a) AS t

making daily report with MySQL

i want to make some daily report which order by date.
i want this data can increase every day.
Date qty QP
2010-09-01 10 10
2010-09-02 3 13 (it means result QP from 2010-09-01 accumulate with 2010-09-02)
2010-09-03 8 21
this is the 1st code:
SELECT Date, SUM(number) AS qty FROM calc GROUP BY Date
how do i do to show "QP" if for actually i dont need to show "qty" field(automatic count) just show Date and QP but it still can count?
SET #r := 0;
SELECT date, #sum := SUM(number) AS qty, #r := #r + #sum AS qp
FROM calc
GROUP BY
date
This example will help you for sure:
MySQL select "accumulated" column