How to get sum/expenditure in salary with minimum query - mysql

Hi here is the sql statement in mySql.
Can any body suggest best mySql statement for the following.
SELECT A.id, A.salary, A.salary+ IFNULL((SELECT SUM(B.salary) FROM test_salary B WHERE B.id < A.id ORDER BY id DESC),0) AS tot FROM test_salary A
How many times this query runs?
- number of rows available is table + 1.
I want result like this:
id salary tot
1 200 200
2 300 500
3 400 900
4 500 1400
5 600 2000
6 700 2700
7 800 3500
8 900 4400
where salary table has only id and salary field.

It is not clear from what you are trying to do here but the following is at least syntactically correct.
SELECT A.id, A.salary,
A.salary+IFNULL((SELECT SUM(B.salary) FROM test_salary B WHERE B.id = a.id),0)
from a
Based on your edit I can see that your query works. The sub query will run for every row encountered in your main query. An alternative is to use a variable
select a.id,a.salary,
#tot := #tot + a.salary as tot
from test_salary a, (select #tot:=0) t;
I suggest you compare your query to this for performance.

Related

MySQL Select records exceeding the cumulative total

Given I have following table
Id
FileSizeMB
1
100
2
100
3
100
4
100
5
100
6
100
I want to select oldest records exceeding a cumulative value, in this case say 500.
So something like this
Id
Cumulative_FileSizeMB
6
100
5
200
4
300
3
400
2
500
1
600
I want to select only records with id 2 and 1 as they are >= 500.
Goal is to delete them.
Thanks
For anyone with same problem.
I have reached this solution using Mysql window functions,
and also there is no need to declare a variable for cumulative total
SELECT * from (
SELECT
id,
FileSizeMB,
SUM(FileSizeMB) OVER (ORDER BY id DESC) AS TotalFileSizeMB
FROM table
) as t1
WHERE TotalFileSizeMB > 500

MySql Select - row subtract previous row

I'm trying to extract stats from DB.
Table's structure is:
UpdatedId product_name revenue
980 Product1 1000
975 Product1 950
973 Product1 900
970 Product1 800
965 Product21 1200
So revenue = previous revenue + new revenue.
In order to make graphs, the goal is to get the output for Product1 like this
UpdateId Difference
980 50
975 50
973 100
970 0
I tried this query but MySQL gets stuck :)
select a.product_name, a.revenue, b.revenue, b.revenue- a.revenue as difference from updated_stats a, updated_stats b where a.product_name=b.product_name and b.revenue= (select min(revenue) from updated_stats where product_name=a.product_name and revenue > a.revenue and product_name= 'Product1')
Could you please tell me, how it should be queried? Thanks.
I would do this with a correlated subquery:
select u.*,
(select u.revenue - u2.revenue
from updated_stats u2
where u2.product_name = u.product_name and
u2.updatedid < u.updatedid
order by u2.updatedid desc
limit 1
) as diff
from updated_stats u;
Note: This returns NULL instead of 0 for 970. That actually makes more sense to me. But you can use COALESCE() or a similar function to turn it into a 0.
If updated_stats is even moderately sized, you will want an index on updated_status(product_name, updated_id, revenue). This index covers the subquery.

HAVING clause and performance

I've got a performance problem with a SQL (MySql) query. Basically I have a table similar to this:
ID PRICE ID OBJECT
-----------------------------
1 500.00 1 1
2 300.00 1 1
3 400.00 1 1
4 100.00 1 1
5 100.00 1 1
6 100.00 2 3
And I need to get the maximum amount of lines given an amount.
For example, given the amount 1000.00 the query must returns these ids (order by price asc) and the total price.
ID PRICE TOTAL_PRICE
---------------------------------
4 100 100.00
5 100 200.00
2 300 500.00
3 400 900.00
Atm I'm using a query similar to the below one:
set #total=0;
select a.id, a.price , #total:=#total + a.price as total_price , a.id_user
from shares a
where a.`id_user` != 0 and a.id_object = 1
having #total < 1000.00 order by a.price asc;
It works fine but it's not efficient. It takes around 1.5 seconds to extract the data (the table has around 1M lines).
The problem is related to the Having clause.
Do you have any suggestions?
Is there a way to perform this type of query without using the clause Having ?
I believe this (cumulative sum) is what you are looking for:
set #total = 0;
SELECT ID,
Price,
Total_Price
FROM (
SELECT a.*
,(#total := #total + price) AS total_price
FROM shares a
WHERE a.id_user != 0
AND a.id_object = 1
ORDER BY a.price
) q1
WHERE q1.total_price < 1000;
SQL Fiddle Demo

Self-Join SQL statement w/calculated data

I have a table with the following data:
id date name schedulenum paymentamt
1 12/2/2014 AB 077LR10 100
2 12/2/2014 AN 077LR10 200
3 12/2/2014 CD 077LR10 300
4 3/10/2015 AN 083LR12 200
5 3/10/2015 WC 083LR12 500
6 5/20/2015 AB 105LR20 200
7 5/20/2015 CD 105LR20 150
8 5/20/2015 RH 105LR20 150
9 5/20/2015 RG 105LR20 400
And I would like to write a query that would bring back the following results:
schedulenum paymentamt
077LR10 600
083LR12 700
105LR20 900
Basically I need to create a SQL statement that selects data from Table A that will result in 2 columns. The first column would be a unique schedule number (i.e., 'schedulenum' - there are multiple rows with the same schedulenum) and a total payment amount ('paymentamt') per schedulenum (each row will have a different 'paymentamt'). I think this would require a self-join but not sure how to do it.
Use a group by when getting sums from one table.
select schedulenum, sum(payment) from mytable
where schedulenum = x
group by schhedulenum
...
select schedulenum, sum(payment) from mytable
group by schhedulenum
order by schedulenum
No self-join needed at all. What you want is the 'group by' keyword and aggregate functions.
SELECT schedulenum, sum(paymentamt)
FROM [TABLE]
GROUP BY schedulenum;

How can I have a column with sum of smaller IDs in MySQL?

Assume I have a table like this:
id pay
-- ---
1 10
2 20
3 30
4 40
5 50
6 60
I want to create a view from table above with this result:
id pay paid_before
-- --- -------------
1 10 0
2 20 10
3 30 30
4 40 60
5 50 100
6 60 150
which "paid_before" is sum of pay rows that have smaller id.
How could I do this job?
This accomplishes what you want.
SELECT p1.id,p1.pay, sum(p2.pay) as Paid_Before FROM PAYMENTS P1 LEFT JOIN
PAYMENTS P2 ON p1.id > p2.id
GROUP BY p1.id, p1.pay
See this sql fiddle
In MySQL, this is most efficiently done with variables:
select p.id, p.pay, (#p := #p + p.pay) - p.pay as PaidBefore
from payments p cross join
(select #p := 0) vars
order by id;
Although this is not standard SQL (which I usually prefer), that is okay. The standard SQL solution is to use cumulative sum:
select p.id, p.pay, sum(p.pay) over (order by p.id) - p.pay as PaidBefore
from payments p;
Many databases support this syntax, but not MySQL.
The SQL Fiddle (courtesy of Atilla) is here.