Given a *students_exam_rooms* table:
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1001 |
| 2 | 30 | 1002 |
| 3 | 31 | 2001 |
| 4 | 32 | 2002 |
| 5 | 33 | 3001 |
| 6 | 33 | 3002 |
| 7 | 34 | 4001 |
| 8 | 34 | 4002 |
+------------+---------+---------+
And *students_tbl*:
+------------+-------------+------+
| student_id | studen_name | year |
+------------+-------------+------+
| 1 | Eric | 1 |
| 2 | Mustafa | 1 |
| 3 | Michael | 2 |
| 4 | Andy | 2 |
| 5 | Rafael | 3 |
| 6 | Mark | 3 |
| 7 | Jack | 4 |
| 8 | peter | 4 |
+------------+-------------+------+
How can I select from *students_exam_rooms* ordering by *students_tbl.year* but with one after one like this:
+--------------+------+
| student_name | year |
+--------------+------+
| Eric | 1 |
| Michael | 2 |
| Rafael | 3 |
| Jack | 4 |
| Mustafa | 1 |
| Andy | 2 |
| Mark | 3 |
| Peter | 4 |
+--------------+------+
I'm assuming that you want to order by the "occurrence-count" of the year then the year, e.g. all the first-occurrences of all years first, sorted by year, then all second-occurrences of all years also sorted by year, and so on. That would be a perfect case for emulating other RDBMS' analytic / windowing functions:
select *
from (
select
s.studen_name,
s.year,
ser.*,
(
select 1 + count(*)
from students_tbl s2
where s.year = s2.year
and s.student_id > s2.student_id
) rank
from students_tbl s
JOIN students_exam_rooms ser
ON s.student_id = ser.student_id
) i_dont_really_want_to_name_this
order by rank, year
Here it is against a slightly tweaked version of JW's fiddle: http://www.sqlfiddle.com/#!2/27c91/1
Emulating Analytic (AKA Ranking) Functions with MySQL is a good article that gives more background and explanation.
try any of these below:
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY REVERSE(b.seat_no),
a.year
SQLFiddle Demo
by using Modulo
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY CASE WHEN MOD(b.seat_no, 2) <> 0 THEN 0 ELSE 1 END,
a.year
SQLFiddle Demo
Looks to me like you're trying to sort first by seat and then by year. Looking at your students_exam_rooms table, it looks like you started with a simple seat number and prepended year * 1000. So, if we omit the year, it looks like this:
> select * from fixed_students_exam_rooms;
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1 |
| 2 | 30 | 2 |
| 3 | 31 | 1 |
| 4 | 32 | 2 |
| 5 | 33 | 1 |
| 6 | 33 | 2 |
| 7 | 34 | 1 |
| 8 | 34 | 2 |
+------------+---------+---------+
And if you had that table, your query is simple:
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
seat_no, year
;
Using the table as you currently have it, it's only slightly more complicated, assuming the "core seat number" doesn't excede 999.
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
convert(substr(seat_no, 2), unsigned),
year
;
Related
I keep track of certain game results in a MySQL database. Now I want to print the latest results in a nice HTML table. I have three tables:
Table persons contains all participants of the game.
+-----+---------+
| id | name |
+-----+---------+
| 2 | Jon |
| 3 | Philip |
| 4 | Tom |
| 5 | Joey |
| 6 | Joanna |
+-----+---------+
The table rounds contains information about each round of the game. Among other things, the week in which the game was fought.
+-----+------+
| id | week |
+-----+------+
| 1 | 9 |
| 2 | 10 |
| 3 | 11 |
| 4 | 12 |
| 5 | 13 |
+-----+------+
And the table results contains the results for each person and round. The result column is a score in the game.
+------------+----------+--------+
| personId | roundId | result |
+------------+----------+--------+
| 2 | 1 | 2 |
| 4 | 1 | 6 |
| 5 | 1 | 6 |
| 3 | 1 | 10 |
| 2 | 2 | 16 |
| 4 | 2 | 14 |
| 5 | 2 | 5 |
| 3 | 2 | 11 |
+------------+----------+--------+
Now I want to print a table with the players scores each week. I want my output to look like the table below. Note that if a player did not participate one week, the cell should be empty.
+------+-----+--------+-----+------+--------+
| Week | Jon | Philip | Tom | Joey | Joanna |
+------+-----+--------+-----+------+--------+
| 9 | 2 | 10 | 6 | 6 | |
| 10 | 16 | 11 | 14 | 5 | |
+------+-----+--------+-----+------+--------+
So my question is: How do I do to get such output?
This is not a duplicate. See comments below.
So as stated in comments, you want to make a PIVOT, but MySQL does not support it.
However since your number of players is low and fixed, you can hardcode the players in a GROUP BY query like this :
SELECT R.Week,
SUM(CASE WHEN P.name = 'Jon' THEN S.result END) AS Jon,
SUM(CASE WHEN P.name = 'Philip' THEN S.result END) AS Philip,
SUM(CASE WHEN P.name = 'Tom' THEN S.result END) AS Tom,
SUM(CASE WHEN P.name = 'Joey' THEN S.result END) AS Joey,
SUM(CASE WHEN P.name = 'Joanna' THEN S.result END) AS Joanna
FROM persons P
LEFT JOIN results S ON P.id=S.personId
LEFT JOIN rounds R ON R.id=S.roundId
WHERE R.week IS NOT NULL
GROUP BY R.Week
SqlFiddleDemo
Consider this data:
---+-----------+-------+--+
| id | name | grade | |
+----+-----------+-------+--+
| 13 | Maria | 10 | |
| 18 | Lorenzo | 10 | |
| 2 | Cissa | 10 | |
| 3 | Neto | 9 | |
| 15 | Gabriel | 9 | |
| 10 | Laura | 9 | |
| 12 | Joãozinho | 8 | |
| 16 | Sergio | 8 | |
| 8 | Adriele | 8 | |
| 6 | Jorgito | 8 | |
| 5 | Aline | 8 | |
| 1 | Cintia | 8 | |
| 19 | Fabiana | 7 | |
| 11 | Vinicius | 7 | |
| 9 | Tatiane | 7 | |
| 7 | Chico | 7 | |
| 4 | Marcos | 7 | |
| 14 | Pedro | 6 | |
| 17 | Mauricio | 6 | |
| 20 | Leonardo | 6 | |
+----+-----------+-------+--+
I need the students with the three biggest grades. I think I need to group the data by grade and limit to the top 3 groups.
"SELECT * FROM student GROUP BY grade LIMIT 3" only gives me 3 rows, that's not what I want.
I've tried to use HAVING to filter the groups, but without success. I don't want to set the filter grade>MAX(grade)-2, because theoretically I will not know the grades. But this filter didn't work anyway.
I'am using MySQL. Please help!
You can do this using a join:
select s.*
from student s join
(select grade
from student
group by grade
order by grade desc
limit 3
) g3
on s.grade = g3.grade;
In most databases, you an do this using in:
select s.*
from student s
where s.grade in (select grade
from student
group by grade
order by grade desc
limit 3
);
However, MySQL seems to reject this syntax.
select s1.*
from students s1
join (select distinct grade from students
order by grade desc limit 3) s2 on s1.grade = s2.grade
Alternatively:
select *
from students
where grade >= (select distinct grade from students
order by grade desc limit 2,1)
select s.*
from student s join
(select top 3 grade
from student
group by grade
order by grade desc
) g3
on s.grade = g3.grade;
i am loosing it over the following problem:
i have a table with participants and points. each participant can have up to 11 point entries of which i only want the sum of the top 6.
in this example lets say we want the top 2 of 3
+----+---------------+--------+
| id | participantid | points |
+----+---------------+--------+
| 1 | 1 | 11 |
+----+---------------+--------+
| 2 | 3 | 1 |
+----+---------------+--------+
| 3 | 3 | 4 |
+----+---------------+--------+
| 4 | 2 | 3 |
+----+---------------+--------+
| 5 | 1 | 5 |
+----+---------------+--------+
| 6 | 2 | 10 |
+----+---------------+--------+
| 7 | 2 | 9 |
+----+---------------+--------+
| 8 | 1 | 3 |
+----+---------------+--------+
| 9 | 3 | 4 |
+----+---------------+--------+
as a result i want something like
+---------------+--------+
| participantid | points |
+---------------+--------+
| 2 | 19 |
+---------------+--------+
| 1 | 16 |
+---------------+--------+
| 3 | 8 |
+---------------+--------+
(it should be ordered DESC by the resulting points)
is this at all possible with mysql? in one query?
oh and the resulting participant ids should be resolved into the real names from another 'partcipant' table where
+----+------+
| id | name |
+----+------+
| 1 | what |
+----+------+
| 2 | ev |
+----+------+
| 3 | er |
+----+------+
but that should be doable with a join at some point... i know...
Using one of the answers from ROW_NUMBER() in MySQL for row counts, and then modifying to get the top.
SELECT ParticipantId, SUM(Points)
FROM
(
SELECT a.participantid, a.points, a.id, count(*) as row_number
FROM scores a
JOIN scores b ON a.participantid = b.participantid AND cast(concat(a.points,'.', a.id) as decimal) <= cast(concat(b.points,'.', b.id) as decimal)
GROUP BY a.participantid, a.points, a.id
) C
WHERE row_number IN (1,2)
GROUP BY ParticipantId
Had an issue with ties until I arbitrarily broke them with the id
i'm build an exercises web app and i'm working with two tables like this:
Table 1: weekly_stats
| id | code | type | date | time |
|----|--------------|--------------------|------------|----------|
| 1 | CC | 1 | 2015-02-04 | 19:15:00 |
| 2 | CC | 2 | 2015-01-28 | 19:15:00 |
| 3 | CPC | 1 | 2015-01-26 | 19:15:00 |
| 4 | CPC | 1 | 2015-01-25 | 19:15:00 |
| 5 | CP | 1 | 2015-01-24 | 19:15:00 |
| 6 | CC | 1 | 2015-01-23 | 19:15:00 |
| .. | ... | ... | ... | ... |
Table 2: global_stats
| id | exercise_number |correct | wrong |
|----|-----------------|--------|-----------|
| 1 | 138 | 1 | 0 |
| 2 | 246 | 1 | 0 |
| 3 | 988 | 1 | 10 |
| 4 | 13 | 5 | 0 |
| 5 | 5 | 4 | 7 |
| 6 | 5 | 4 | 7 |
| .. | ... | ... | ... |
What i would like is to get MAX(correct-wrong) and MIN(correct-wrong) and now i'm working with this query:
SELECT
exercise_number,
date,
time
FROM weekly_stats AS w JOIN global_stats AS g
ON w.id=g.id
WHERE correct - wrong = (SELECT MAX(correct - wrong) from global_stats)
UNION
SELECT
exercise_number,
date,
time
FROM weekly_stats AS w JOIN global_stats AS g
ON w.id=g.id
WHERE correct - wrong = (SELECT MIN(correct - wrong) from global_stats);
This query is working good, except for one thing: when "WHERE correct - wrong = (SELECT MIN(correct - wrong)[...]" selects more than one row, the row selected is the first but i would like to have returned the most recent (in other words: ordered by datetime(date, time)). Is it possible?
Thanks!
I think you can solve it like this:
SELECT * FROM (
SELECT
1 as sort_column,
exercise_number,
date,
time
FROM weekly_stats AS w JOIN global_stats AS g
ON w.id=g.id
WHERE correct - wrong = (SELECT MAX(correct - wrong) from global_stats)
ORDER BY date DESC, time DESC
LIMIT 1 ) as a
UNION
SELECT * FROM (
SELECT
2 as sort_column,
exercise_number,
date,
time
FROM weekly_stats AS w JOIN global_stats AS g
ON w.id=g.id
WHERE correct - wrong = (SELECT MIN(correct - wrong) from global_stats)
ORDER BY date DESC, time DESC
LIMIT 1) as b
ORDER BY sort_column;
Here is the documentation about how UNION works.
I have one table like below
|order_item_id|order_id|customer_id|
| 2 | 30 | 9 |
| 3 | 30 | 9 |
| 4 | 30 | 9 |
| 5 | 30 | 9 |
| 11 | 32 | 9 |
| 12 | 32 | 9 |
| 13 | 32 | 9 |
here i would like to count total number of order_item_id for each order_id using mysql.
please help
Try this:
select order_id, count(*) from t
group by order_id
Edit:
yes this one i knew it, but actually i would like to list out all related records as well, not just count. – user804457
After the requirements changed, then this seems to be what you're looking for:
select * from t t1
join (
select order_id, count(*) aCount from t
group by order_id
) t2
on t1.order_id = t2.order_id
Result:
+---------------+----------+-------------+--------+
| ORDER_ITEM_ID | ORDER_ID | CUSTOMER_ID | ACOUNT |
+---------------+----------+-------------+--------+
| 2 | 30 | 9 | 4 |
| 3 | 30 | 9 | 4 |
| 4 | 30 | 9 | 4 |
| 5 | 30 | 9 | 4 |
| 11 | 32 | 9 | 3 |
| 12 | 32 | 9 | 3 |
| 13 | 32 | 9 | 3 |
+---------------+----------+-------------+--------+
select order_item_id, count(order_id)
from orders
group by order_id
You need to use GROUP BY, like this:
SELECT order_item_id, COUNT(order_item_id) FROM your_table GROUP BY (order_id)
See the official documentation here: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html