Sub groups within Group By query in mysql - mysql

My table is as follows
a | b
--|--
0 | 5
1 | 6
2 | 7
3 | 7
4 | 7
I want to sum over 'b' for groups (a = 0, a = 1, a >= 2).
Sample output should be something like,
sum | a
----|---
5 | 0
6 | 1
21 | 2
What query should I be using?

That should do it:
SELECT
CASE
WHEN a = 0 THEN '0'
WHEN a = 1 THEN '1'
WHEN a >= 2 THEN '2'
END AS anotherNameThanA,
SUM(b) AS `sum`
FROM yourTable
GROUP BY anotherNameThanA

Related

Calculate a running sum in MySQL that increments when a field = 1 and decrements by 1 when that same field = 0

Hello I am new to MySQL and I am having trouble creating the following MySQL Query. I have a table that looks like this:
id TestCase PassFail
1 tc_a 1
2 tc_b 0
3 tc_c 1
4 tc_a 0
5 tc_c 1
6 tc_b 1
7 tc_a 1
8 tc_a 1
I want to write a query that creates a table that is a running sum of the PassFail field. This field should increment by 1 whenever a unique test case first passes or toggles between fail and pass and decrement by 1 whenever a test case toggles between pass and fail. The sum should not change when the new status of a test case remains the same. The output table for my example should look like:
id TestCase PassFail passSum note (not in output table)
1 tc_a 1 1 first pass for tc_a, increment by 1
2 tc_b 0 1 fail for tc_b, no change
3 tc_c 1 2 first pass for tc_c, increment by 1
4 tc_a 0 1 toggled pass to fail tc_a, decrement by 1
5 tc_c 1 1 no change for tc_c, no change
6 tc_b 1 2 toggled fail to pass tc_b, increment by 1
7 tc_a 1 3 toggled fail to pass tc_a, increment by 1
8 tc_a 1 3 no change for tc_a, no change
I was able to create a running total that increments whenever a new test case passes by using DISTINCT but I can't figure out how to get it to decrement when that unique test case fails. Any help or suggestions would be much appreciated!
Your edit helps tremendously.
drop table if exists t;
create table t(id int, TestCase varchar(10), PassFail int);
insert into t values
(1 , 'tc_a' , 1),
(2 , 'tc_b' , 0),
(3 , 'tc_c' , 1),
(4 , 'tc_a' , 0),
(5 , 'tc_c' , 1),
(6 , 'tc_b' , 1),
(7 , 'tc_a' , 1),
(8 , 'tc_a' , 1);
In the sub query s below I work out a combined status for each test case using a sub query with a limit clause. The outer query then uses a variable to calculate passsum based on the combined status. I think only 01 and 10 are of interest and I have not tested extensively but the result does match your desired output.
select s.id,s.testcase,s.passfail,s.combined,
case
when combined = 01 then #passsum:=#passsum + 1
when combined = 10 then #passsum:=#passsum - 1
else #passsum:=#passsum
end passsum
from
(
select t.ID,t.testcase,t.passfail,
concat (
case
when (select passfail from t t1 where t1.testcase = t.testcase and t1.id < t. id order by t1.ID limit 1) is null then 0
else (select passfail from t t1 where t1.testcase = t.testcase and t1.id < t. id order by t1.ID desc limit 1)
end,
t.passfail
) as combined
from t
order by t.testcase,t.id
) s
cross join (select #passsum:=0) a
order by s.id;
+------+----------+----------+----------+---------+
| ID | testcase | passfail | combined | passsum |
+------+----------+----------+----------+---------+
| 1 | tc_a | 1 | 01 | 1 |
| 2 | tc_b | 0 | 00 | 1 |
| 3 | tc_c | 1 | 01 | 2 |
| 4 | tc_a | 0 | 10 | 1 |
| 5 | tc_c | 1 | 11 | 1 |
| 6 | tc_b | 1 | 01 | 2 |
| 7 | tc_a | 1 | 01 | 3 |
| 8 | tc_a | 1 | 11 | 3 |
+------+----------+----------+----------+---------+

MYSQL condition inside case not working

I have two tables: Here is the
sqlfiddle (http://sqlfiddle.com/#!9/5a51734/5)
1) [table:data_aoc]
| aoc_id | aoc_name | aoc_type | client_id |
|------------------------------|-----------|
1 | MA01 | sensor_1 | 4 | 1 |
2 | MA02 | sensor_2 | 15 | 1 |
2) table:data_log
| log_id | log_aoc_id | trans_type | trans_value | trans_date |
|-------------------------------------------------------------|
1 | x1a1 | MA01 | 0 | 90 | 2017-10-20 |
2 | afaf | MA01 | 0 | 90 | 2017-10-21 |
3 | va12 | MA02 | 0 | 10 | 2017-10-21 |
4 | gag2 | MA02 | 0 | 10 | 2017-11-25 |
Expected Result
Total value for MA02 should be 10 but it shows 20
my queries as follows
SELECT
(CASE
WHEN a.aoc_type IN ('4')
THEN IFNULL((SUM(b.trans_value * case b.trans_type when '0' then -1 else 1 end)),0)
WHEN a.aoc_type IN ('15')
THEN IFNULL((SUM(b.trans_value * case when b.trans_type='0' AND DATE(b.trans_date) <= DATE(NOW()) then -1 else 1 end)),0)
END) as total
FROM data_aoc a
LEFT JOIN data_log b ON b.log_aoc_id = a.aoc_id
WHERE a.client_id='1'
GROUP BY a.aoc_name
ORDER BY a.aoc_id asc
Iam expecting when aoc_type is (15) it will sum the value within the date condition
DATE(b.trans_date) <= DATE(NOW())
but when i execute the queries, it produce result not within the date condition. *some timestamps are generated in advance beyond the NOW() date time.
The desired result should be:
| Total |
|-------|
| -180 |
| 10 |
But i get
| Total |
|-------|
| -180 |
| 0 | <----- it should be 10 because of the date condition i put
thank you!
As a follow-up of same findings from Don, And your clarification of don't count after, I came up with this query... Pre-check on the date first and if after, multiply by zero, OTHERWISE, apply the +/- 1 factor.
SELECT
SUM( b.trans_value *
CASE when ( a.aoc_type = '15'
AND b.trans_type = '0'
AND DATE(b.trans_date) > DATE(NOW()) )
then 0
when ( a.aoc_type = '4'
AND b.trans_type = '0' )
OR ( a.aoc_type = '15'
AND b.trans_type = '0'
AND DATE(b.trans_date) <= DATE(NOW()) )
then -1 else 1 end ) as total
FROM
data_aoc a
LEFT JOIN data_log b
ON a.aoc_id = b.log_aoc_id
WHERE
a.client_id='1'
GROUP BY
a.aoc_name
ORDER BY
a.aoc_id asc
Also posted on SQL Fiddle
It seems to be working exactly as it should.
With the date clause I get:
Sensor 1 = -180
Sensor 2 = 0
If you break down the summing you get two rows to be summed for sensor #2
10 on 10-21 (before the date restriction so it's multiplied by -1)
and
10 on 11-25 (after the date restriction so it's multiplied by 1)
10 * -1 + 10 * 1 = 0
The sensor #2 reading is correctly 0.
I do not understand why you think it should be anything else.

Rails+ActiveRecords: How to group records by date and show their count based on a condition?

I have data like this in a DB table
ID | numbers | created_at
1 | 10 | 2016-04-01
2 | 20 | 2016-04-01
3 | -8 | 2016-04-01
4 | 1 | 2016-04-02
5 | 81 | 2016-04-03
6 | -12 | 2016-04-03
7 | 0 | 2016-04-03
And the desired output I'd like to get:
Date | Greater (or even) than 0 | Smaller than 0
2016-04-01 | 2 | 1
2016-04-02 | 1 | 0
2016-04-03 | 2 | 1
Is there a way to load this data from one query?
All I can think of our subqueries and doing queries in the Rails view where I want to render the fetched data.
I would try something like this:
lines = Model.
select('date, SUM(IF(number > 0, 1, 0)) as greater_count', SUM(IF(number < 0, 1, 0)) as smaller_count').
group(:date).
order(:date)
lines.each do |line|
puts [line.date, line.greater_count, line.smaller_count]
end
Assuming your Created_at is a date with no time components... similar to spickermann's but less platform specific.
Select Created_at as Date
, Sum(case WHEN numbers >= 0 THEN 1 Else 0 END) as GTE_0
, Sum(case WHEN numbers < 0 THEN 1 Else 0 END) as LT_0
FROM Table
GROUP BY Created_at
What this does is evaluate the number if >=0 then it sets a value of 1 which it then sums by date for Greater than Equal to 0 (GTE_0) Similar done for LT_0 (Less than 0).

MySQL subtracting successive rows in same column

My question is similar to this SO post however the difference is that I do not have a sequential ID column.
I have a table in the following form
ID | length
0 | 5
0 | 7
0 | 10
1 | 3
1 | 8
1 | 12
2 | 1
2 | 2
2 | 4
2 | 5
and I want to get the difference between successive rows in the length column grouped by the ID. So it should give
ID | length | difference
0 | 5 | NULL
0 | 7 | 2
0 | 10 | 3
1 | 3 | NULL
1 | 8 | 5
1 | 12 | 4
2 | 1 | NULL
2 | 2 | 1
2 | 4 | 2
2 | 5 | 1
I'm not sure how to go about doing this. I tried giving each ID a separate ID that is sequential, but it turned out to be way to complicated and I could not get it to work. Can someone suggest a better way of doing it?
Assuming (id,length) is UNIQUE...
SELECT x.*
, x.length - MAX(y.length) diff
FROM my_table x
LEFT
JOIN my_table y
ON y.id = x.id
AND y.length < x.length
GROUP
BY x.id
, x.length;
select a.id, a.length, b.length, b.length - a.length as difference
from mytable a, mytable b
where a.id=b.id
and b.length = (select min(length) from mytable where id=a.id and length > a.length)

mysql condition in a select

My table:
id | elite | pos
1 | 0 | 9
2 | 1 | 8
3 | 0 | 7
4 | 1 | 6
5 | 0 | 5
6 | 1 | 4
7 | 0 | 3
8 | 1 | 2
9 | 0 | 1
10 | 1 | 0
I have this simple query
SELECT id, elite FROM tbl LIMIT 0, 5 ORDER BY pos DESC
It will return the id 1 2 3 4 5. Over time, these values were to change. The result must have always a count of 5, however if on the result there are at least one id with an elite >= 1, the result must not contain any more id with an elite having the 1 value. So the result must not contain id having more than one elite >= 1.
Is this possible within a query?
You can use UNION to combine two queries, like so:
(SELECT * FROM tbl WHERE elite = 1 LIMIT 1)
UNION
(SELECT * FROM tbl WHERE elite = 0)
ORDER BY pos DESC LIMIT 5
It will give the results you need.
Check out Mysql reference for UNIONs