I have a table 'questions' with columns
userid
qid(question id)
answer
The questions are multiple choice so not every question has the same number of answers a user can choose from.
question 100 might have 4 answers to choose from.
question 200 might have 6 answers to choose from.
question 300 might have 2 answers to choose from.
etc
So the table might look something like this:
+-------- --+---------+--------+
| userid | qid | answer |
+---- ------+---------+--------+
| 1 | 100 | 4 |
| 1 | 200 | 6 |
| 1 | 300 | 1 |
| 1 | 400 | 4 |
| 2 | 100 | 1 |
| 2 | 400 | 6 |
| 3 | 200 | 4 |
| 3 | 400 | 4 |
| 3 | 100 | 1 |
| 4 | 100 | 1 |
| 4 | 400 | 6 |
| 5 | 200 | 1 |
| 5 | 400 | 6 |
+-----------+---------+--------+
I want to know what's the count for the most given answer for question 100, what's the count for the second highest answer for question 100 , what's the count for the 3rd highest answer for question 100, etc
I've can't figure how to query this and not sure if this is possible.
I would the results to be something like:
+------+----+----+----+----+----+----+----+
| qid |ans1|ans2|ans3|ans4|ans5|ans6|ans7|
+------+----+----+----+----+----+----+----+
| 100 | 3 | 0 | 0 | 1 | 0 | 0 | 0 |
| 200 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 300 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 400 | 0 | 2 | 0 | 0 | 0 | 3 | 0 |
+------+----+----+----+----+----+----+----+
Group by the questions and then you can use aggregate functions like sum() that apply to each group. And you can use a condition in sum() to do conditional summing
select qid,
sum(answer = 1) as ans1,
sum(answer = 2) as ans2,
sum(answer = 3) as ans3,
sum(answer = 4) as ans4,
sum(answer = 5) as ans5,
sum(answer = 6) as ans6,
sum(answer = 7) as ans7,
count(*) as total
from your_table
group by qid
Related
After adding the WITH ROLLUP in the GROUP BY statement the ranges reordered. How can this be fixed?
Here is the code
SUM(product.product_id = 1) AS Soda,
SUM(product.product_id = 2) AS Liquor,
SUM(product.product_id = 3) AS Lemon,
SUM(product.product_id = 4) AS Mango,
SUM(product.product_id = 5) AS Inhaler,
SUM(1) AS Count
FROM line_item
JOIN product USING (product_id)
JOIN ( SELECT 0 lowest, 500 highest UNION
SELECT 501 , 1000 UNION
SELECT 1001 , 1500 UNION
SELECT 1501 , 2000 UNION
SELECT 2001 , 2500 ) ranges ON product.price * line_item.quantity BETWEEN ranges.lowest AND ranges.highest
GROUP BY Revenue WITH ROLLUP;
Result:
+-------------+------+--------+-------+-------+---------+-------+
| Revenue | Soda | Liquor | Lemon | Mango | Inhaler | Count |
+-------------+------+--------+-------+-------+---------+-------+
| 0 - 500 | 4 | 0 | 4 | 0 | 1 | 9 |
| 1001 - 1500 | 0 | 1 | 0 | 2 | 2 | 5 |
| 1501 - 2000 | 0 | 2 | 0 | 0 | 1 | 3 |
| 2001 - 2500 | 0 | 1 | 0 | 0 | 0 | 1 |
| 501 - 1000 | 0 | 0 | 0 | 2 | 0 | 2 |
| NULL | 4 | 4 | 4 | 4 | 4 | 20 |
+-------------+------+--------+-------+-------+---------+-------+
The range 501 - 1000 moved to the bottom, it should be next to the 0-500 range.
The column Revenue is a string so the results are sorted alphabetically.
In order to sort the column as a number, a solution would be to cast Revenue to a number like:
ORDER BY Revenue IS NULL, Revenue + 0
but as I tested in MySql 8.0.22 here (with a previous fiddle of your data), for some reason, it does not work (maybe a bug?).
In any case you should try it too.
The code that worked is this:
GROUP BY ranges.lowest, ranges.highest WITH ROLLUP
HAVING GROUPING(ranges.lowest) = 1 OR GROUPING(ranges.highest) = 0
ORDER BY GROUPING(ranges.lowest), ranges.lowest
See the demo.
Results:
> Revenue | Soda | Liquor | Lemon | Mango | Inhaler | Count
> :-------- | ---: | -----: | ----: | ----: | ------: | ----:
> 0-500 | 4 | 0 | 4 | 0 | 1 | 9
> 501-1000 | 0 | 0 | 0 | 2 | 0 | 2
> 1001-1500 | 0 | 1 | 0 | 2 | 2 | 5
> 1501-2000 | 0 | 2 | 0 | 0 | 1 | 3
> 2001-2500 | 0 | 1 | 0 | 0 | 0 | 1
> null | 4 | 4 | 4 | 4 | 4 | 20
This question already has answers here:
Aggregate ad clicks and views
(2 answers)
Closed 3 years ago.
Say I have a table log with format [prodName, status]
An example set be:
| ProdName | Status
|-----------------------
| AXD1 | 100
| BL1 | 100
| AXD2 | 300
| BL2 | 300
| AXD1 | 300
| AXD2 | 100
| BL1 | 100
| BL1 | 100
I will the result group by status where 100 is success and 300 not. So the result like this.
| ProdName | Success | Not
|-----------------------
| AXD1 | 1 | 1
| BL1 | 3 | 0
| AXD2 | 1 | 1
| BL2 | 0 | 1
You could use case expressions to find if a row was a success or not, and then count them:
SELECT ProdName,
COUNT(CASE Status WHEN 100 THEN 1 END) AS "Success",
COUNT(CASE Status WHEN 300 THEN 1 END) AS "Not Success"
FROM mytable
GROUP BY ProdName
You can use conditional aggregation:
select
ProdName,
sum(Status = 100) Success,
sum(Status = 300) `Not`
from Log
group by ProdName
See the demo.
Results:
| ProdName | Success | Not |
| -------- | ------- | --- |
| AXD1 | 1 | 1 |
| AXD2 | 1 | 1 |
| BL1 | 3 | 0 |
| BL2 | 0 | 1 |
Query to get results from 2 tables:
SELECT path.* FROM (SELECT tbc.course_name
slp.course_id,slp.student_type,slp.stu_reference_id,
count(slp.course_id) as counttotalWatchedStudents
from tbl_student_learning_path slp LEFT JOIN tbl_courses tbc
on tbc.course_pid = slp.course_id WHERE slp.stu_reference_id =34
and slp.student_type='institute' GROUP BY slp.course_id ) as path
Query result table:
| course_id | totalCollegeStudents | fullwatchedStudentsCount | counttotalWatchedStudents | sumOfWatchPointsForWatchedStudents | totalStudentsAvg | fullwatchedAvg |
|-------------------------------|----------------------|--------------------------|---------------------------|------------------------------------|------------------|----------------|
| Number Systems | 9 | 0 | 3 | 60 | 20.0000 | 0 |
| Percentages | 9 | 0 | 3 | 30 | 10.0000 | 0 |
| Blood Relations | 9 | 3 | 3 | 300 | 100.0000 | 300 |
| Calandar | 9 | 3 | 3 | 300 | 100.0000 | 300 |
| Percentages | 9 | 3 | 3 | 300 | 100.0000 | 300 |
| Permutation & Combination | 9 | 3 | 3 | 300 | 100.0000 | 300 |
| Probability | 9 | 0 | 3 | 90 | 30.0000 | 0 |
| Ratios | 9 | 0 | 3 | 120 | 40.0000 | 0 |
| Time and Work | 9 | 0 | 3 | 150 | 50.0000 | 0 |
| Time Speed & Distance | 9 | 1 | 3 | 140 | 46.6667 | 100 |
| Averages | 9 | 3 | 3 | 300 | 100.0000 | 300 |
| Coding and Decoding | 9 | 3 | 3 | 300 | 100.0000 | 300 |
From the above table, i want to add inner query to the main query
query should be something like this:
( select count(t1.watched_percentage) from tbl_student_learning_path t1
WHERE t1.stu_reference_id =34 and t1.student_type='institute'
AND t1.watched_percentage >= 90 group by t1.course_id )
fullwatchedStudentsCount,
And the result should come like this(this is nothing but if first table counttotalWatchedStudents value is 3 it means that there are 2 type of people
1.students watched full (watched_percentage>=90)
2.students still watching (watched_percentage 1-89)
)
| fullwatchedStudentsCount | fullwatchedStudentsSum |
|--------------------------|------------------------|
| 2 | 200 |
| 1 | 100 |
| 0 | 0 |
| 2 | 200 |
| 1 | 100 |
| 1 | 100 |
| 0 | 0 |
| 2 | 200 |
| 2 | 200 |
| 1 | 100 |
| 2 | 200 |
| 1 | 100 |
If I understand correctly you want sum up the students which saw more than 90% in another column:
I'd do it like this:
SELECT tbc.course_name,
slp.course_id,
slp.student_type,
slp.stu_reference_id,
count(slp.course_id) AS counttotalWatchedStudents,
sum(if(slp.watched_percentage>=90, 1, 0)) AS fullwatchedStudentsCount
sum(if(slp.watched_percentage>=90, watched_percentage, 0)) AS fullwatchedStudentsSum
FROM tbl_student_learning_path slp
LEFT JOIN tbl_courses tbc ON tbc.course_pid = slp.course_id
WHERE slp.stu_reference_id =34
AND slp.student_type='institute'
GROUP BY slp.course_id
enter code here
Hope this helps
So you want to count students with a watched_percentage >= 90? Use conditional aggregation for this:
SELECT
tbc.course_name,
slp.course_id,
slp.student_type,
slp.stu_reference_id,
COUNT(*) as counttotalWatchedStudents,
SUM(slp.watched_percentage >= 90) as fullwatchedStudentsCount,
SUM(slp.watched_percentage < 90) as stillwatchedStudentsCount
FROM tbl_student_learning_path slp
LEFT JOIN tbl_courses tbc ON tbc.course_pid = slp.course_id
WHERE slp.stu_reference_id = 34
AND slp.student_type= 'institute'
GROUP BY slp.course_id;
MySQL treats true = 1 and false = 0, so you can simply sum the trues :-)
I have a DB where I have stored a table with user information, a table with test (answers and points) and a table with user's answers for each question. Each question is worth in total 1 point and could have one or more correct answers. If all of the answers are correct, and the user check just one, he will receive just 0.25 points.
I want to make a query to check total points for each user, but I don't find a good method.
User table:
+--------+------------+-----------+-------------------+------------+--------+
| userID | first_name | last_name | email | password | points |
+--------+------------+-----------+-------------------+------------+--------+
| 1 | Jhon | Jhonny | jhon#yahoo.com | secretPass | 0 |
| 2 | Dan | Dan | dan#yahoo.com | 1234 | 0 |
| 3 | Dick | Pop | dd#yahoo.com | 123456 | 0 |
| 4 | Mihaela | Micky | mihaela#yahoo.com | pass12 | 0 |
+--------+------------+-----------+-------------------+------------+--------+
Question table:
(1 means that answer is good - we can have multiple correct answers)
+------------+--------------------------------------------------+---+---+---+---+
| questionID | question | a | b | c | d |
+------------+--------------------------------------------------+---+---+---+---+
| 1 | which of these are colors? | 1 | 0 | 0 | 1 |
| 2 | which of these are fruits? | 1 | 1 | 1 | 0 |
| 3 | which of these are programming language? | 0 | 1 | 1 | 0 |
| 4 | What is IPv6? | 0 | 0 | 0 | 1 |
+------------+--------------------------------------------------+---+---+---+---+
User's answer table:(1 means the user choose that answer but may be inccorect )
+------------+--------+---+---+---+---+
| questionID | userID | a | b | c | d |
+------------+--------+---+---+---+---+
| 1 | 1 | 1 | 1 | 0 | 0 |
| 2 | 1 | 1 | 1 | 1 | 0 |
| 1 | 3 | 1 | 0 | 1 | 1 |
| 1 | 4 | 1 | 1 | 1 | 0 |
| 3 | 1 | 1 | 0 | 1 | 1 |
| 4 | 1 | 1 | 0 | 1 | 1 |
| 1 | 2 | 1 | 1 | 0 | 0 |
| 2 | 2 | 0 | 1 | 0 | 1 |
| 3 | 2 | 0 | 1 | 1 | 1 |
| 4 | 2 | 1 | 1 | 0 | 1 |
| 2 | 3 | 1 | 0 | 0 | 1 |
| 3 | 3 | 1 | 0 | 1 | 1 |
| 4 | 3 | 1 | 0 | 1 | 1 |
| 2 | 4 | 0 | 1 | 1 | 1 |
| 3 | 4 | 1 | 0 | 0 | 1 |
| 4 | 4 | 0 | 0 | 1 | 0 |
+------------+--------+---+---+---+---+
Try this
SELECT
a.*,
u.name,
q.*,
# (a.a & q.a) + (a.b & q.b) + (a.c & q.c) + (a.d & q.d) userCorrects,
# (a.a + a.b + a.c + a.d) questionCorrects,
((a.a & q.a) + (a.b & q.b) + (a.c & q.c) + (a.d & q.d)) / (a.a + a.b + a.c + a.d) as userGrade
FROM
answer a
INNER JOIN
user u ON a.userID = u.id
INNER JOIN
question q ON a.questionID = q.id
You'd join questions and answers and add up correct answers. The formula per answer is simply: number of correct answers divided by 5. You'd GROUP BY user ID and SUM to get results per user.
select u.userid, u.first_name, u.last_name, counted.points
from
(
select
a.userid,
sum(((a.a = q.a) + (a.b = q.b) + (a.c = q.c) + (a.d = q.d) + (a.e = q.e)) / 5)
as points
from question q
join answer a on a.questionid = q.questionid
group by a.userid
) counted
join users u on u.userid = counted.userid;
In MySQL true = 1 and false = 0, so (a.a = q.a) is 1 when correct and 0 when wrong.
Nice question...!!!
I think this query will help you with all possible cases that may occur in this scenario.
SELECT
u.userID, u.first_name, u.last_name, u.email,
SUM(1 - ((!(answer.a = question.a)) + (!(answer.b = question.b)) + (!(answer.c = question.c)) + (!(answer.d = question.d))) * 0.25) AS Score
FROM answer
INNER JOIN
user u ON answer.userID = u.userID
INNER JOIN
question ON answer.questionID = question.questionID
GROUP BY answer.userID
I have 2 tables bellow
0 --> Pending
1 --> Success
2 --> Fail
table : mntnc
+-------+-------+-------+
| id | own | sts |
+-------+-------+-------+
| 1 | BN | 1 |
| 2 | BB | 2 |
| 3 | BN | 1 |
| 4 | BD | 1 |
| 5 | BD | 0 |
table : istlsi
+-------+-------+-------+
| id | own | sts |
+-------+-------+-------+
| 1 | BN | 1 |
| 2 | BB | 1 |
| 3 | BB | 1 |
| 4 | BC | 0 |
| 5 | BD | 2 |
of the two tables above, I want to add both of them to be the table below
+-------+-----------+-----------+-----------+
| own | success | fail | pending |
+-------+-----------+-----------+-----------+
| BN | 3 | 0 | 0 |
| BB | 2 | 1 | 0 |
| BD | 1 | 1 | 1 |
| BC | 0 | 0 | 1 |
The two key points here:
Union tables (I aliased result to B)
Use sum(case...) for each column.
First we union both tables together as an inline view.
We then use a case statement for each desired column and evaluate the status setting the value to 1 or 0 depending on sts value. and then sum those...
SELECT own
, sum(case when sts=1 then 1 else 0 end) as Success
, sum(case when sts=2 then 1 else 0 end) as Fail
, sum(case when sts=0 then 1 else 0 end) as Pending
FROM ( SELECT ID, own, sts
FROM mntnc
UNION ALL
SELECT id, own, sts
FROM istlsi
) B
GROUP BY own