i have 2 table like this
student
|-----------------------|
| id | name | value |
|-----------------------|
| F01 | Ruben | 4 |
| F02 | Dani | 2 |
| F03 | Mike | 3 |
| F04 | John | 4 |
|-----------------------|
tutor
|-------------------------|
| id | code | student_id |
|-------------------------|
| 1 | S2244 | F01 |
| 2 | S3251 | F02 |
| 3 | S2244 | F03 |
| 4 | S2244 | F04 |
|-------------------------|
note, tutor.code ( S2244 and S3251) is foreign key from another table, tutor.student_id is foreign key from student table, how to make the two tables combined and produce a result as below?
|-----------------------|
| id | name | value |
|-----------------------|
| F01 | Ruben | 4 |
| F03 | Mike | 3 |
| F04 | John | 4 |
|-----------------------|
the result is the same as the student table, but the data is released based on what is stored in the tutor table, in the tutor table there is code "S3251" / "F02" which is not displayed in the results table
this is like the "WHERE" condition but the WHERE 'condition ' is used in other tables, I've tried using JOIN but i can't, or maybe my table design is wrong? Please help, this code that I made but didn't get a good result
SELECT st.id, st.name, st.value FROM student st JOIN tutor tt ON tt.code = 'S2244'
You can use exists:
select s.*
from students s
where exists (
select 1 from tutor t where t.student_id = s.student_id and t.code = 'S2244'
)
This makes more sense than a join, since you are not selecting from the tutor table).
The problem with your original attempt is that you are missing a joining condition on student_id (which is common to both tables). The syntax would be:
select s.*
from student s
inner join tutor t on s.id = t.student_id
where t.code = 's2244'
In addition to #GMB's answer above, which is absolutely correct, you could also do the following, which I think might be more intuitive for a beginner developer:
select * from student
where id in (
select student_id from tutor where id = 's2244'
)
Related
i have 2 table like this
student
|-----------------------|
| id | name | value |
|-----------------------|
| F01 | Ruben | 4 |
| F02 | Dani | 2 |
| F03 | Mike | 3 |
| F04 | John | 4 |
|-----------------------|
tutor
|---------------------------------|
| id | code | student_id | class |
|---------------------------------|
| 1 | S2244 | F01 | IF-B |
| 2 | S3251 | F02 | IF-B |
| 3 | S2244 | F03 | IF-A |
| 4 | S2244 | F04 | IF-C |
|---------------------------------|
note, tutor.code ( S2244 and S3251) is foreign key from another table, tutor.class ( IF-B, IF-A, IF-C ) is foreign key from another table too, tutor.student_id is foreign key from student table, how to make the two tables combined and produce a result as below?
|-------------------------------|
| id | name | value | class |
|-------------------------------|
| F01 | Ruben | 4 | IF-B |
| F03 | Mike | 3 | IF-A |
| F04 | John | 4 | IF-C |
|-------------------------------|
I want to take all the columns in the student table and combine them with the "class" column in the tutor table.
I have tried it myself but can only display data from the student table, and the "class" column of the tutor table cannot appear, this is the query I made
select s.*
from students s
where exists (
select 1 from tutor t where t.student_id = s.student_id and t.code = 'S2244'
)
I would just use an inner join here:
SELECT
s.id,
s.name,
s.value,
t.class
FROM student s
INNER JOIN tutor t
ON s.id = t.student_id
WHERE
t.code = 'S2244';
hellow.I have 3 table like below;
Movie Table like this:
+------+-------+-----+
| id | name | |
+------+-------+-----+
+------+-------+-----+
| 1 | got | |
+------+-------+-----+
+------+-------+-----+
| 2 | Drive | |
+------+-------+-----+
+------+-------+-----+
| 3 | Thor | |
+------+-------+-----+
Janra:
+------+-------------+
| id | janra_name |
+------+-------------+
+------+-------------+
| 1 | action |
+------+-------------+
+------+-------------+
| id | comedy |
+------+-------------+
Movie_janra: (movie_id is a foreign key to id in movie table)
+--------+-------------+
| mov_id | janra_id |
+--------+-------------+
+--------+-------------+
| 1 | 1 |
+--------+-------------+
+--------+-------------+
| 1 | 2 |
+--------+-------------+
nation Table:
+------+-------------+
| id | name |
+------+-------------+
+------+-------------+
| 1 | us |
+------+-------------+
+------+-------------+
| 2 | uk |
+------+-------------+
movie_nation Table:
+------+-------------+
|mov_id| nation_id |
+------+-------------+
+------+-------------+
| 1 | 1 |
+------+-------------+
+------+-------------+
| 1 | 2 |
+------+-------------+
then i use query like this:
SELECT *
FROM
(SELECT movie.id,
movie.name,
f.janra_name
FROM `movie`
LEFT JOIN
(SELECT mj.movie_id,
janra.janra_name
FROM movie_janra AS mj
LEFT JOIN janra ON mj.janra_id=janra.id) AS f ON f.movie_id=movie.id) AS ll
LEFT JOIN
(SELECT movie_nation.movie_id,
nation.nation
FROM movie_nation
INNER JOIN nation ON nation.id=movie_nation.nation_id) AS rr ON rr.movie_id=ll.id
(join movie with result of (movie_janra and janra)) AS ll this give me all movies with all janra like below
id name janra
1 got action
1 got comedy
then i join this with result of (join movie_nation with nation) AS rr ON rr.movie_id = ll.id
but this query result is like this
+-----------+-------------+-------------+----------+
| id | name | janra | nation |
+-----------+-------------+-------------+----------+
+-----------+-------------+-------------+----------+
| 1 | got | action | us |
+-----------+-------------+-------------+----------+
+-----------+-------------+-------------+----------+
| 1 | got | action | uk |
+-----------+-------------+-------------+----------+
+-----------+-------------+-------------+----------+
| id | name | comedy | us |
+-----------+-------------+-------------+----------+
+-----------+-------------+-------------+----------+
| id | name | comedy | uk |
+-----------+-------------+-------------+----------+
I use MySQL.
This result is more than I want. I want two row. Thank you all.
First thing, remove the tables movie_nation and movie_janra then just move the columns to movie table as shown below then retain all the other tables:
Database tables
4: https://i.stack.imgur.com/Mf6MU.png
then I have added table data:
movie table
Janra table
Nation table
Then use this code to get your desired output:
select a.id,a.movie_name,b.janra_name, c.nation_name
from movie a
left outer join janra b
on a.janra_id = b.id
left outer join nation c
on a.nation_id = c.id;
Just select the ID and Movie name to movie table then left outer join to nation and janra table using their corresponding IDs from table movie to get the janra_name and nation_name.
This is the ouput of it: query output here
based on the previous answer, you just need to change the data type of janra_id and nation_id from movie table from int to varchar. then you can now use multiple janras and nation using comma separated values.
use this new code to achieve that.
select a.id, a.movie_name, GROUP_CONCAT(distinct a.janra_name) janra_name,
GROUP_CONCAT(distinct a.nation_name) nation_name
from (
select a.*,b.janra_name,c.nation_name
from movie a
left outer join janra b
on FIND_IN_SET(b.id, a.janra_id)
left outer join nation c
on FIND_IN_SET(c.id, a.nation_id)
order by a.movie_name ) a
group by a.movie_name;
Here is the sample data:
And here is the output of the query:
I have a database with 3 tables: students, courses and mistakes. I have one joining table (csm) where I connect the 3 tables. I am supposing mistakes are the same for each course.
Table Courses
+----------+---------------+
| crs_id | crs_name |
+----------+---------------+
| 1 | HTML |
| 2 | PHP |
| 3 | Python |
+----------+---------------+
Table Students
+----------+---------------+---------------+
| stu_id | stu_firstname | stu_lastname |
+----------+---------------+---------------+
| 1 | Tina | Turner |
| 2 | Lisa | Laroi |
| 3 | Dina | Donna |
| 3 | Jim | Leduc |
+----------+---------------+---------------+
Table Mistakes
+----------+---------------+------------+
| mis_id | mis_name | mis_weight |
+----------+---------------+------------+
| 1 | No camelCase | 7 |
| 2 | No brackets | 10 |
| 3 | Operator mist.| 12 |
+----------+---------------+------------+
Joining table CSM
+----------+------------+------------+------------+
| csm_id | fk_crs_id | fk_stu_id | fk_mis_id |
+----------+------------+------------+------------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 3 |
| 3 | 2 | 3 | 1 |
| 4 | 3 | 2 | 2 |
| 5 | 3 | 2 | 1 |
| 6 | 3 | 3 | 1 |
+----------+------------+------------+------------+
If I select a specific course, I want to get a list of ALL students with the minus points for this course. So I also want to get the students with no result in the joining table csm.
The closest result I got is with the following sql statement:
select stu_firsname, stu_lastname, csm.*, sum(mis_weight)
from students s
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id
left join mistakes m on csm.fk_mis_id = m.mis_id
where fk_crs_id = 4 or fk_crs_id is null
group by stu_firstname;
With this I get the sum of the mistakes for a certain course and also the students who don't have any records in CSM table, but some results are missing. For example, this doesn't show the students who have records in the CSM table, but not for the requested course.
How do I get these students in my result table?
In your query :
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id`
...
where fk_crs_id = 4 or fk_crs_id is null
This is not exactly what you want, since this condition will filter out students that have records in the csm table for only courses other than 4. You want to move that condition to the corresponding LEFT JOIN:
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id AND csm.fk_crs_id = 4
Another potential source of problems is the way the query handles aggregation. There are non-aggregated columns in the SELECT clause that do not appear in the GROUP BY clause. This syntax is not good SQL coding practice, and is not supported anymore since version 5.7 of MySQL. I assumed that you want to one record in the result for each student.
Query:
select
s.stu_firstname,
s.stu_lastname,
sum(m.mis_weight) total_misses_weight
from
students s
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id AND csm.fk_crs_id = 3
left join mistakes m on csm.fk_mis_id = m.mis_id
group by
s.stu_id,
s.stu_firstname,
s.stu_lastname
Demo on DB Fiddle for course id 3:
| stu_firstname | stu_lastname | total_misses_weight |
| ------------- | ------------ | ------------------- |
| Tina | Turner | |
| Lisa | Laroi | 17 |
| Dina | Donna | 7 |
| Jim | Leduc | |
if your primary data's is in CSM table, try this:
select s.stu_firsname, s.stu_lastname, csm.*, sum(m.mis_weight) from crs_stu_mis csm
join students s on s.stu_id = csm.fk_stu_id
join mistakes m on csm.fk_mis_id = m.fou_id
csm.fk_crs_id = 4
group by s.stu_naam;
Second case:
Your data's can affected by group by attribute, try attribute that it is not NULL , ex:
select s.stu_firsname, s.stu_lastname, csm.*, sum(m.mis_weight) from crs_stu_mis csm
join students s on s.stu_id = csm.fk_stu_id
join mistakes m on csm.fk_mis_id = m.fou_id
csm.fk_crs_id = 4
group by csm.csm_id;
I have these two tables:
Student:
| name | email |
|---------------------|-------------------------|
| Arturo Vidal | arturo.vidal#usm.cl |
| Bastian Quezada | bastian#usm.cl |
| Javier Jeria | javier#usm.cl |
| Sebastian Piñera | sebastian#presidente.cl |
| Sebastian Gallardo | sebastian#usm.cl |
Class:
| classId | email | signUpDate |
|---------|-------------------------|-------------|
| 1 | sebastian#usm.cl | 2018-01-01 |
| 1 | javier#usm.cl | 2019-10-01 |
| 1 | bastian#usm.cl | 2018-07-01 |
| 2 | sebastian#usm.cl | 2018-05-04 |
| 2 | bastian#usm.cl | 2018-01-01 |
| 3 | bastian#usm.cl | 2018-12-05 |
| 3 | sebastian#usm.cl | 2018-02-01 |
| 4 | arturo.vidal#usm.cl | 2018-03-01 |
| 5 | sebastian#presidente.cl | 2018-03-01 |
I want to show the name the last student that signed up for each classId. That means, I should get a name for classId 1, one for classId 2, etc. My solution for firstly getting the mails (to know the student's name after) is this:
select classId, email, max(signUpDate)
from Class
group by classId
it prints the max date, which is ok, but it also prints the wrong mails for each date:
| ClassId | email | max(signUpDate) |
|---------|-------------------------|-----------------|
| 1 | sebastian#usm.cl | 2019-10-01 |
| 2 | sebastian#usm.cl | 2018-05-04 |
| 3 | bastian#usm.cl | 2018-12-05 |
| 4 | arturo.vidal#usm.cl | 2018-03-01 |
| 5 | sebastian#presidente.cl | 2018-03-01 |
which is completely wrong (). Therefore, when I try to join the the values for getting the names, I get incorrect values.
In other words, I don't understand why are the rows mixing up. Is there any solution for getting correct emails for the max(signUpDate) for each ClassId?
Thanks for your time
i have created the test data fiddle and made an easy and understandable query to fetch the required data, i.e:
SELECT DISTINCT classId,
std.name,
Class.email,
signUpDate
FROM CLASS
INNER JOIN Student std ON std.email = Class.email
WHERE signUpDate IN
(SELECT max(signUpDate)
FROM CLASS
GROUP BY classId)
Sql Fiddle here
This is an instance of a very common class of questions: find the whole row FOR EACH GROUP of the field that maximizes some value (in the group). In your case, you want to GROUP BY the ClassId, and FOR EACH ONE OF THESE GROUPS, you want the whole row of the field with the maximum signupDate.
SHORT ANSWER: You can use this query:
SELECT
C.ClassId,
S.name
FROM
(
SELECT A.*
FROM Class AS A
LEFT JOIN Class AS B
ON A.email = B.email AND A.signupDate < B.signupDate
WHERE B.email IS NULL
) AS C
LEFT JOIN Student AS S ON S.email=C.email
LONG ANSWER:
Here you can find a very clear explanation of what I have just said.
Assuming that we can use the e-mail at your tables as unique identifier, you can do FIRST a join (on the e-mail field) of the table "Class" with itself, to select the "maximum date" for each class id. After that, you join (on the e-mail field) with the table "Student". After that, you will have a table with all the fields of the "Class" table and all the fields of the "Student" table. You can select the fields that you need. In the following example, I will select "Class.classId" and "Student.name"
If you run this query:
SELECT A.*
FROM Class AS A
LEFT JOIN Class AS B
ON A.email = B.email AND A.signupDate < B.signupDate
WHERE B.email IS NULL
You obtain this table:
+---------+-------------------------+------------+
| ClassId | email | signupDate |
+---------+-------------------------+------------+
| 1 | javier#usm.cl | 2019-10-01 |
| 2 | sebastian#usm.cl | 2018-05-04 |
| 3 | bastian#usm.cl | 2018-12-05 |
| 4 | arturo.vidal#usm.cl | 2018-03-01 |
| 5 | sebastian#presidente.cl | 2018-03-01 |
+---------+-------------------------+------------+
Now you can join this with the table "Student", and select the fields that you want. If you run the query provided in the "short answer" part of this post, you get the following result:
+---------+--------------------+
| ClassId | name |
+---------+--------------------+
| 4 | Arturo Vidal |
| 3 | Bastian Quezada |
| 1 | Javier Jeria |
| 5 | Sebastian Piñera |
| 2 | Sebastian Gallardo |
+---------+--------------------+
Try this:
SELECT A.classId, C.name, C.email, B.signUpDate
FROM
(SELECT classId, max(signUpDate) maxSignUpDate
FROM Class
GROUP BY classId) A JOIN Class B
ON A.classId=B.classId AND A.maxSignUpDate=B.signUpDate
JOIN Student C ON C.email=B.email;
I assume the email to be the ID field of the Student table. See MySQL Join Made Easy and MySQL GROUP BY for insights.
See it run on SQL Fiddle.
I have three tables. Two of them are separate irrelevant tables (students and subjects), the third (entries) is one which links them both with foreign keys (student_id and subject_id).
Here are all the tables with the records:
students:
+------------+------------+-----------+---------------------+---------------------+
| student_id | first_name | surname | email | reg_date |
+------------+------------+-----------+---------------------+---------------------+
| 1 | Emily | Jackson | emilym#gmail.com | 2012-10-14 11:14:13 |
| 2 | Daniel | ALexander | daniela#hotmail.com | 2014-08-19 08:08:23 |
| 3 | Sarah | Bell | sbell#gmail.com | 1998-07-04 13:16:32 |
| 4 | Alex | Harte | AHarte#hotmail.com | 1982-06-14 00:00:00 |
+------------+------------+-----------+---------------------+---------------------+
subjects:
+------------+--------------+------------+----------------+
| subject_id | subject_name | exam_board | level_of_entry |
+------------+--------------+------------+----------------+
| 1 | Art | CCEA | AS |
| 2 | Biology | CCEA | A |
| 3 | Computing | OCR | GCSE |
| 4 | French | CCEA | GCSE |
| 5 | Maths | OCR | AS |
| 6 | Chemistry | CCEA | GCSE |
| 7 | Physics | OCR | AS |
| 8 | RS | CCEA | GCSE |
+------------+--------------+------------+----------------+
entries:
+----------+---------------+---------------+------------+
| entry_id | student_id_fk | subject_id_fk | entry_date |
+----------+---------------+---------------+------------+
| 1 | 1 | 1 | 2012-10-15 |
| 2 | 1 | 4 | 2011-09-21 |
| 3 | 1 | 3 | 2015-08-10 |
| 4 | 2 | 6 | 1992-07-13 |
| 5 | 3 | 7 | 2013-02-12 |
| 6 | 3 | 8 | 2016-01-14 |
+----------+---------------+---------------+------------+
How would I go about selecting the names of all the students (students.first_name), and the name (subjects.subject_name) of whichever subject entries they have? What I mean is that all student names are returned, and all the subject names for their entries listed beside them, with NULL for those which don't have any entries. I also want it grouped by the first_name alphabetically.
I want the output to be something like:
first_name subject_name
--------------------------
Alex NULL
Daniel Chemistry
Emily French
Emily Computing
Sarah Physics
Sarah RS
though I'm not sure if that's entirely correct.
My guess is it's like this:
SELECT students.first_name, subjects.subject_name
FROM students
JOIN entries ON entries.student_id_fk = students.student_id
JOIN subjects ON entries.subject_id_fk = subjects.subject_id
GROUP BY students.first_name;
Really the only thing I'm not sure about is which join to use and where to put it, or if the tables need to be listed in a different order. I'm thinking it should be a left join but I'm not sure.
Help is much appreciated!
You should use left join since you want to return also row for student that has no subject assigned. Plus you want to sort the result, not group. So in the end should be like this:
SELECT students.first_name, subjects.subject_name
FROM students
LEFT JOIN entries ON entries.student_id_fk = students.student_id
LEFT JOIN subjects ON entries.subject_id_fk = subjects.subject_id
ORDER BY students.first_name;
I think this could be the query but use order by and not group by (group by is for aggregate function like count() or max() )
SELECT students.first_name, subjects.subject_name
FROM entries
LEFT JOIN students ON entries.student_id_fk = students.student_id
LEFT JOIN subjects ON entries.subject_id_fk = subjects.subject_id
ORDER BY students.first_name;
You likely want a LEFT OUTER JOIN:
select stu.first_name, sub.subject_name
from students stu
join entries e
on stu.student_id = e.student_id_fk
left outer join subjects sub
on sub.subject_id = e.subject_id_fk
order by stu.first_name;
I'm away from my PC with any SQL installed, so this is untested, but should give you what you want.
Modified my answer to replace the group by with an order by as pointed out by the others. That is the proper way to do it, unless the group is there as part of a larger query that you may have trimmed out.
Left join students table on the remaining two tables sequentially is the right choice to grab all the students first name.
To order the names order by should be used.
I have create a sql fiddle for better visualization of how to get the desired output.
Here is the link: http://sqlfiddle.com/#!9/a1c850/7
The query is
select students.student_name, subjects.subject_name
from
students
left join entries on entries.student_id=students.student_id
left join subjects on entries.subject_id=subjects.subject_id
order by students.student_name;