Subtract from one number dynamically - mysql

I have a base number 30000 and about 5 rows, where every row have different number and i want to subtract them from the base number in query.
I want to achieve the result column:
ID| num | result
1 | 1000 | 29000
2 | 1200 | 27800
3 | 2100 | 25700
4 | 4300 | 21400
5 | 1100 | 20300

SET #num := 0;
SELECT
id,
num,
IF(#num = 0,#num := (30000 - num) , #num := (#num - num)) AS `Result`
FROM
`mytable`
Demo

Try this:
SELECT id, num, (30000 - #sum:=#sum+num) AS Result
FROM mytable, (SELECT #sum:= 0) AS A
Check this SQL FIDDLE DEMO

Related

how to return last row in specific sum?

imagine we have 1 row which is students that contain, id, name, marks and rank. write query that return the last name of student where marks is equal to 100 ordered by grade.
example
- id | name | marks | grade |
- 01 | Jeff | 40 | 1 |
- 02 | Annie| 40 | 3 |
- 03 | Ramy | 20 | 5 |
- 04 | Jenny| 20 | 2 |
so the result should return
Annie
because Annie is the last row of the sum of marks where marks is equal to 100. Jeff is the first cause based on grade he's equal to 1 so he should be entered first, second is Jenny and third is Annie. Jeff(40)+Jenny(20)+Annie(40) = 100
You can make a running sum MySQL's user variable.
This query should work from MySQL 5.1 and up.
Query
SELECT
Table1_alias.name
FROM (
SELECT
Table1.name
, (#running_marks_sum := #running_marks_sum + Table1.marks) AS running_marks_sum
FROM
Table1
CROSS JOIN (SELECT #running_marks_sum := 0) AS init_user_param
ORDER BY
Table1.grade ASC
) AS Table1_alias
WHERE
Table1_alias.running_marks_sum = 100
Result
| name |
| ----- |
| Annie |
View on DB Fiddle
MySQL 8.0+ only
Query
SELECT
Table1_alias.name
FROM (
SELECT
Table1.name
, SUM(Table1.marks) OVER(ORDER BY Table1.grade) AS running_marks_sum
FROM
Table1
) AS Table1_alias
WHERE
Table1_alias.running_marks_sum = 100;
Result
| name |
| ----- |
| Annie |
View on DB Fiddle
Keep the cumulative sum of marks to a variable. And use this as a sub-query and select the row having the total is 100. But if no row having the cumulative total as 100, then wont't get any result.
Query
set #total := 0;
select `id`, `name`, `marks`, `grade` from(
select `id`, `name`, `marks`, `grade`, (#total := #total + `marks`) as `total`
from `your_table_name`
order by `grade`
) as `t`
where `t`.`total` = 100;
As mentioned the database structure above, Below is one of the way to get the output
select name from (select * from (SELECT id,name,grade,marks, #total := #total + marks AS total FROM (stud, (select #total := 0) t) order by grade ) t WHERE total <=100 ) final_view order by grade desc limit 1

Mysql Select records from a table loop group by field

I have a table with products.
The table has a companyId field.
Let's describe it like this:
id --- companyId
1 | 2
2 | 3
3 | 4
4 | 2
5 | 3
6 | 1
7 | 4
I want to select all the records ordered by companyId but with the company id looping, as so:
id --- companyId
6 | 1
1 | 2
2 | 3
3 | 4
4 | 2
5 | 3
7 | 4
How can I achieve it?
You can achieve this using MySQL user defined variables
SELECT
t.id,
t.companyId
FROM
(
SELECT
*,
IF(#sameCompany = companyId , #rn := #rn + 1,
IF(#sameCompany := companyId, #rn := 1,#rn := 1)
) AS rn
FROM companytable
CROSS JOIN (SELECT #sameCompany := -1, #rn := 1) AS var
ORDER BY companyId
) AS t
ORDER BY t.rn , t.companyId
See Demo
Explanation:
First sort the data according to companyId so that the same company ids stick together.
Now take a walk along this sorted result and assign a sequentially increasing row number every time you see the same companyId otherwise assign 1 as row number.
Now name this sorted result (with row number) t.
Finally sort these data (t) according to ascending row number and ascending companyId.

MySQL top 2 records per group

Basically I need to get only the last 2 records for each user, considering the last created_datetime:
id | user_id | created_datetime
1 | 34 | '2015-09-10'
2 | 34 | '2015-10-11'
3 | 34 | '2015-05-23'
4 | 34 | '2015-09-13'
5 | 159 | '2015-10-01'
6 | 159 | '2015-10-02'
7 | 159 | '2015-10-03'
8 | 159 | '2015-10-06'
Returns (expected output):
2 | 34 | '2015-10-11'
1 | 34 | '2015-09-10'
7 | 159 | '2015-10-03'
8 | 159 | '2015-10-06'
I was trying with this idea:
select user_id, created_datetime,
$num := if($user_id = user_id, $num + 1, 1) as row_number,
$id := user_id as dummy
from logs group by user_id
having row_number <= 2
The idea is keep only these top 2 rows and remove all the others.
Any ideas?
Your idea is close. I think this will work better:
select u.*
from (select user_id, created_datetime,
$num := if(#user_id = user_id, #num + 1,
if(#user_id := id, 1, 1)
) as row_number
from logs cross join
(select #user_id := 0, #num := 0) params
order by user_id
) u
where row_number <= 2 ;
Here are the changes:
The variables are set in only one expression. MySQL does not guarantee the order of evaluation of expressions, so this is important.
The work is done in a subquery, which is then processed in the outer query.
The subquery uses order by, not group by.
The outer query uses where instead of having (actually, in MySQL having would work, but where is more appropriate).

Select quantity of record instances separated by weeks

I have a table like the below:
CompanyID | Logged | UniqueID
A | 2014-06-24 | 8
B | 2014-06-24 | 7
A | 2014-06-16 | 6
B | 2014-06-16 | 5
A | 2014-06-08 | 4
B | 2014-06-08 | 3
A | 2014-06-01 | 2
B | 2014-06-01 | 1
I'm stuck trying to create an SQL statement that will return the quantity of rows found for each unique CompanyID, separated into 4 week periods, so something like the below:
CompanyID | Period (week) | Quantity
A | 0 | 1
B | 0 | 1
A | 1 | 1
B | 1 | 1
A | 2 | 1
B | 2 | 1
A | 3 | 1
B | 3 | 1
I have done something similar before, except by the last 7 days instead of last 4 weeks, but am not sure if this can be reworked:
select CompanyID,
case DATE_FORMAT(Logged, '%Y%m%d')
when '20140618' then '0'
when '20140619' then '1'
when '20140620' then '2'
when '20140621' then '3'
when '20140622' then '4'
when '20140623' then '5'
when '20140624' then '6'
end as period ,
count(UniqueID) as quantity from TABLE
where DATE_FORMAT(Logged, '%Y%m%d')
in (20140618,20140619,20140620,20140621,20140622,20140623,20140624) group by CompanyID,
DATE_FORMAT(Logged, '%Y%m%d')
Is there a more straightforward way to obtain the output desired above?
Maybe something like this?
SQL FIDDLE to test with
Theres the original query that doesn't use any hard coding... that is generally a really bad practice. it will have the count inflated by 1 since it starts with one and you want it to start with zero so to fix this do a select of the original query where you fix the count and then also not show the user defined variable
SELECT CompanyID, Period - 1 as Period, Quantity FROM(
SELECT
CompanyID,
if(#a = Logged, #b, #b := #b + 1) as Period,
COUNT(*) as Quantity,
#a := Logged
FROM test
JOIN (SELECT #a := '', #b := 0) as temp
GROUP BY UniqueID
ORDER BY Period
) as subQuery
ORIGINAL QUERY
SELECT
CompanyID,
if(#a = Logged, #b, #b := #b + 1) as Period,
COUNT(*) as Quantity,
#a := Logged
FROM test
JOIN (SELECT #a := '', #b := 0) as temp
GROUP BY UniqueID
ORDER BY Period

MySQL Change SUM value

I'm trying to create a query whereby I SUM a column but, if a column contains a certain value, the SUM value has to be reset at that point to take on this value.
ie:
SUM(i.units * op.add_or_subtract) // This would translate to: '50 * -1' or '50 * 1'
The idea is that if op.op_code = 9, the SUM value should be reset to the current value of i.units as a manual adjustment has taken place.
op_code | units | add_or_subtract | SUM value |
--------|-------|-----------------|------------
1 | 50 | 1 | 50
1 | 50 | 1 | 100
4 | 30 | -1 | 70
9 | 225 | 0 | 225
etc etc.
Can anyone help with how I could (if I can) achieve this in MySQL?
try
select *, case when op_code = 9
then #s := units
else (#s := #s + (units * add_or_subtract))
end as sum
from your_table, (select #s := 0) st
try this:
SELECT SUM(IF(op_code = 9, (#var_sum := units),
((#var_sum := #var_sum + units) * add_or_subtract)
) as sum_value
FROM table_name, (SELECT #var_sum := 0) a;