sql calculate percentage over grouped data - mysql

I have a table X like this,
student ans_status question_id
1 1 10
2 -1 10
3 1 10
4 0 10
1 -1 11
2 1 11
3 -1 11
4 -2 11
expected o/p is
10 2/3
11 1/3
etc..
Now, i want the data fro each question 10 like,
number of 1's/(total of 1's and -1's for each question)
I have tried this,
select (select count(student_id) from X
where question_id=10 and ans_status=1) / count(student_id)
from X
where question_id=10
group by ans_status
having ans_status in(1,-1).
i can do it in a nested query, by again selecting and grouping according to the status condition, but is there any way better to do this?
please note i want this for all questions in the table

You can just do:
select question_id,
avg(ans_status = 1)
from X
where ans_status in (1, -1)
group by question_id;
This uses the MySQL feature that a boolean expression is treated as an integer in a numeric context. "True" is 1 and "false" is 0, so the average turns out to be the percentage that are true.
If you want the values independently:
select question_id,
sum(ans_status = 1), count(*)
from X
where ans_status in (1, -1)
group by question_id;

Use GROUP BY for taking count of each question_id for getting count of answer_id is 1 or -1.
Query
select t.`question_id`,
t.`count_1` / t.`total_count` as `new_col` from(
select `question_id`,
sum(case `ans_status` when 1 then 1 when -1 then 1 else 0 end) as `count_1`,
count(*) as `total_count`
from `your_table_name`
group by `question_id`
)t;
Find a demo here

Related

Query to find the additional value in a table based on condition in MySQL

I have a table below
Id
group
value
1
A
11
2
A
3
2
B
2
2
C
3
2
D
2
3
D
8
4
A
6
4
C
6
I would like to display the result
Id
value
Additional Value
1
8
3
2
8
2
3
8
0
4
8
4
MySQL Query
SELECT id ,
SUM(VALUE),
SUM( CASE WHEN (day_type = 'R' AND (VALUE) > 8) THEN (VALUE - 8) WHEN (day_type = 'R' AND (VALUE) <= 8) THEN 0 ELSE 0 END) AS additional_value
FROM TABLE
GROUP BY id
I would like to split the value, into value and additional value, if the value is> 8 I need to add the extra value in the additional value column, My query works for a single row with a value > 8 but with multiple combinations, it does not work.
Could anyone give me a solution for this? Thanks for the help.
Use the functions LEAST() and GREATEST() to compare the total of value for each id to 8:
SELECT id,
LEAST(SUM(value), 8) value,
GREATEST(SUM(value) - 8, 0) additional_value
FROM tablename
GROUP BY id;
See the demo.
You can use LEAST() and GREATEST(). For example:
select
id,
least(sum(value), 8) as value,
greatest(0, sum(value) - 8) as additional_value
from t
group by id

Kind of simple query in mysql but can't solve it

I previously posted a question here: Mysql query with joined tables problems
but didn't get good answers, so I thought I break it down to show only the part that gives me a headache, I might get answers faster to this question, and if I can solve this, I can solve the previous problem too.
The values are referring to an item_id, and I want to get item_id's where the item is referring to (('good' OR 'bad') AND 'fast')
So item_id 1 must be listed, because it is good and also fast
item_id 2 should not listed because it is not fast.
The result i want to get
item_id
1
5
if I have a table like this
id item_id value
1 1 'good'
2 1 'fast'
3 2 'good'
4 2 'slow'
5 3 'good'
6 3 'slow'
7 4 'bad'
8 4 'slow'
9 5 'bad'
10 5 'fast'
11 6 'moderate'
12 6 'fast'
Can someone help me?
One way to see this is: you want a statement per item, so you aggregate and group by item. Criteria come in the HAVING clause.
select item_id
from mytable
group by item_id
having count(case when value = 'fast' then 1 end) >= 1
and count(case when value in ('good','bad') then 1 end) >= 1;
(You can also use sum(case when value = 'fast' then 1 else 0 end) >= 1 or max(case when value = 'fast' then 1 else 0 end) = 1 or some expression along those lines. COUNT(expression) counts expressions that are not null. As I am omitting an ELSE branch, a non-matching record results in null and is thus not counted. Some prefer SUM, some prefer COUNT - it's finally a matter of personal preference.)
One way to do this is with an EXISTS query.
Here's an example:
select t1.item_id
from your_table t1
where t1.value = 'fast'
and exists (
select NULL
from your_table t2
where t2.item_id = t1.item_id
and t2.value in ('good','bad')
);
Considering that a item can be good or bad, not both, I would use the simple way:
select item_id your_table
where value in ('good','bad','fast')
group by item_id
having count(*) = 2
count should be always 2 in those cases.

Selecting sum of three consecutive values in a same row in the table in MYSQL

plz refer the table to provide the sql query to get result like that.
id value
1 10
2 15
3 30
4 10
5 11
6 12
Desired output:
id value
1 55
2 33
http://sqlfiddle.com/#!9/21cbc8
Divide id by 3, round it up, group it (with a sum):
SELECT
ceiling(id / 3) AS NewID,
sum(Value) AS SumValue
FROM MyTable
GROUP BY ceiling(id / 3)
With a variable:
SET #GroupVar = 3; -- Set this number to whatever you want to group by
SELECT
ceiling(id / #GroupVar) AS NewID,
sum(Value) AS SumValue
FROM MyTable
GROUP BY ceiling(id / #GroupVar);

MYSQL Count entries and group by two criteria with output in to a 2d table

I have a table that looks something like this;
(actual table is larger with several million rows)
Test_table
ID Day Value
=============
1 1 4
2 1 -1
3 1 27
4 1 3
5 1 -2
6 1 -5
7 1 3
8 1 1
9 1 1
10 1 Null
11 2 1
12 2 1
13 2 2
14 2 -1
15 2 -3
I want to produce a table of these two columns with the count of the number of times each entry appears, a 2d table with the day down the rows, and the values across the top with each cell containing the count of entries in that criteria like the below;
Desired output
Day Null -5 -3 -2 -1 1 2 3 4 27
==================================================================================
1 1 1 1 1 2 2 1 1
2 1 1 2 1
A query like;
select day, value, count(*) as count
from test_Table
group by day, value
Order by day asc, value desc
;
produces the data as many rows and only 3 columns... How can I get the desired output?
You can do this with conditional aggregation:
select day,
sum(value is NULL) as "NULL",
sum(value = -5) as "-5",
sum(value = -3) as "-3",
sum(value = -2) as "-2",
sum(value = -1) as "-1",
sum(value = 1) as "1",
sum(value = 2) as "2",
sum(value = 3) as "3",
sum(value = 4) as "4",
sum(value = 27) as "27"
from test_Table
group by day
Order by day asc;
Note two things. First, the column values are fixed. If you want dynamic column names, then you need to use dynamic SQL. Second, instead of blanks this will have 0 for the days with no count of a particular value.
The short answer is that it can't be done in MySQL.
The reason is that a SELECT statement has to specify the number of columns to be returned, a name and datatype for each column. And MySQL cannot dynamically generate columns to be returned for you.
The longer answer is that you would need a query of the form:
SELECT t.Day
, SUM(IF(t.value IS NULL,1,0)) AS `Null`
, SUM(IF(t.value = -5 ,1,0) AS `-5`
, SUM(IF(t.value = -3 ,1,0) AS `-3`
, ...
FROM mytable t
GROUP BY t.Day
with each column specified in the SELECT list.
One trick you can use is to use another, separate query to help write that query you need. This has to be a separate step, a separate query. To get the list of values you want returned as column headers would be of the form:
SELECT IFNULL(v.value,'Null') AS val
FROM mytable v
GROUP BY v.value
ORDER BY IF(v.value IS NULL,0,1), v.value
If you are doing this just in MySQL (and not an application), you can have MySQL help generate the required SQL text for you (using SQL to generate SQL)
SELECT CONCAT(' , SUM(IF(t.value',
IFNULL(v.value,' IS NULL',CONCAT(' = ',v.value)),
',1,0)) AS `',v.value,'`'
) AS expr
FROM mytable v
GROUP BY v.value
ORDER BY IF(v.value IS NULL,0,1), v.value
Then copy the string values returned from the expr column, paste those into an editor, and finish creating the SQL statement, like the example shown above.
The answer from Gordon shows the expression IF(col=12,1,0) can be abbreviated to col=12.
I always find myself typing that out the IF(conditional,valtrue,valfalse), but that's just the way my brain works. It's just easier for me to read.
Similarly the expression in the ORDER BY in my example...
ORDER BY IF(v.value IS NULL,0,1)
could be rewritten...
ORDER BY v.value IS NOT NULL

SUM of rows in My Sql with condition

My Data is
ID SCORE
1 55
1 -1
1 25
1 -1
1 -1
1 35
2 25
2 -1
2 65
2 55
2 21
2 -1
Now i want to add/sum the score of each id ignoring -1 and i am trying with this code which is not working
SELECT SUM(CASE when SCORE>-1 THEN SUM(SCORE) ELSE 0 END)
FROM jbit WHERE htno='$id'
Here i am already using WHERE so how can i use another WHERE, if i use multiple Where in single query it may effect other processes.. please help me out
Help me out friends
if there is only two column then there is no need to use SUM, you can try below
SELECT id, IF(SCORE=-1,0,SCORE) AS scoreSum
FROM table1
GROUP BY id
Working DEMO
alternative ( not tested )
SELECT id, SUM(IF(SCORE=-1,0,SCORE)) AS scoreSum
FROM table1
WHERE htno =$id
GROUP BY id
SELECT SUM(score) AS score_sum
FROM jbit
WHERE htno='$id'
AND score <> -1 ;
SELECT SUM(`SCORE`)
FROM `jbit`
WHERE `htno` = '$id'
`SCORE` > 0;
Though, I'd suggest you to change '$id' to just $id if the column type of htno is INTEGER.
SELECT SUM(score) FROM <tablename> WHERE score != -1