Mysql Help - Left join - mysql

I usually read other threads and this is my first question here. Here goes;
I'm trying to build a query that involves two tables, the course table and the studentsLink table. The StudentsLink table describes the link between students and the course. The tables are as below;
Course
courseID(bigint) - PK
courseName (varchar)
courseInstructor (varchar)
StudentsLink
courseID(bigint) - PK
StudentID(bigint) - PK
Below is some sample data;
course table
ID | courseName| courseInstructor
----------------------------------
1 | Algebra 1 | Mike
2 | English 2 | James
3 | English 3 | John
4 | Algebra 2 | Mike
5 | History 1 | Tony
Studentlink table
studentID | courseID
----------------------
100 | 2
101 | 3
102 | 3
102 | 4
103 | 4
100 | 1
103 | 3
103 | 2
The desired outcome is as below given if I was looking for student number 103
ID | courseName| courseInstructor |StudentID | CourseID
---------------------------------------------------------
1 | Algebra 1 | Mike | NULL | NULL
2 | English 2 | James | 103 | 2
3 | English 3 | John | 103 | 3
4 | Algebra 2 | Mike | 103 | 4
5 | History 1 | Tony | NULL | NULL
The query that I have so far is as below;
SELECT *
FROM course
LEFT JOIN studentLink
ON course.courseID = studentLink.courseID
WHERE studentLink.studentID = 103 OR (studentLink .studentID IS NULL AND studentLink.courseID IS NULL)
ORDER BY studentLink.courseID DESC
I'm basically trying to get a result set of out all the courses available, which one is the particular student registered in and which one is he not so I will be able to display it as a course which we can offer to the student.
I have tried many variations of this query and did some research. I'm not exactly asking for teh codez but a little bit of guidance would be wonderful. I've been stuck at this for a few days while trying to work other parts of the project at the same time.
Any help is much appreciated. Thanks in advance.

SELECT ID, CourseName, CourseInstructor, StudentId, CourseId
FROM Courses as c
LEFT JOIN StudentLink as sl ON c.id = sl.CourseId And StudentId = 103

The problem here is that you're joining then filtering, you need to filter at the point of the join
SELECT *
FROM course
LEFT JOIN studentLink
ON course.courseID = studentLink.courseID and studentLink.studentID = 103
ORDER BY course.courseID DESC
This should work (assuming mysql lets you have multiple predicates on the join logic, think it does but don't have an instance to test on)
Failing that you can join to a subquery that applies the restriction for you.
SELECT *
FROM course
LEFT JOIN
(select * from studentLink where studentID = 103) as sl
ON course.courseID = sl.courseID
ORDER BY course.courseID DESC

You can easily get the ones that the student is in using your left join (w/o the or in the where)
You can then get the others where using a not in as a part of a union...
after your frist part of the query you could do something like...
SELECT * FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID WHERE studentLink.studentID = 103
union
select * FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID
WHERE courseID NOT IN ( select course.courseID FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID WHERE studentLink.studentID = 103)
That will probably take some tweaking, i'm not sure of the exact syntax, but it's a possible idea of how to obtain what you need.

Related

Writing complex MySQL Join query

This may be simple for some, but I cannot work it out.
I have 3 tables:
Teams, Users, Tags
Teams Users Tags
------------------- ------------------ -----------------------
userID | teamUserID userID | username userID | name | value
------------------- ------------------ -----------------------
1 | 2 1 | dan 2 | myTag | 1
1 | 3 2 | bob 2 | aTag | 2
1 | 4 3 | jon 3 | bTag | 1
4 | rob 4 | cTag | 5
Each team can have a number of users in it, and each user can own a number of tags.
I need a query which will provide a list of users in any given team, with a total number of tags they have.
So when I request results from team 1 (dan's team) it should return this:
-----------------------------------
userID | username | tagTotalValue
-----------------------------------
2 | bob | 3
3 | jon | 1
4 | rob | 5
I have this query so far, but it just gives me one record with an overall total for the whole team, rather than a list of all the users in the team separately with their totals.
SELECT username, SUM(value) tagTotalValue
FROM users u LEFT JOIN tags t
ON u.userID = t.userID
WHERE u.userID IN (SELECT teamUserID FROM teams WHERE userID = 1)
Help!
If anyone can explain a good way of working out how to build these queries, I would be very grateful to learn. Do I just need to do a mySQL course, or is there a simple method I can employ?
I need a query which will provide a list of users in any given team,
with a total number of tags they have.
This seems to have little to do with the query you have written. You should start by joining the three tables together and then aggregating. The query looks something like this:
SELECT t.teamId, u.userId, u.username, count(ta.userId) as numTags
FROM teams t JOIN
users u
ON t.teamUserID = u.UserId LEFT JOIN
tags ta
ON u.userID = ta.userID
WHERE t.teamId = #teamId -- this can be removed
GROUP BY t.teamId, u.userId, u.username;
This query makes the leap that teams has a column that identifies the team -- say teamId.

sql - how to get courses with module=5

I'm trying to get all courses which has only "module=5", any different course. As you can see below I have 4 courses, such as, course 2, 3, 4, 5. But just two of them has only "module=5", e.g. course 2, 5.
+----+--------+--------+
| id | course | module |
+----+--------+--------+
| 1 | 2 | 5 |
| 2 | 3 | 5 |
| 3 | 3 | 11 |
| 4 | 4 | 5 |
| 5 | 4 | 3 |
| 6 | 5 | 5 |
| 7 | 4 | 6 |
| 8 | 4 | 5 |
+----+--------+--------+
I've tryed do two queries, in the first I return all courses which has module=5 and in the second I return all courses which has module!=5, then I save in 2 files and execute the unix command diff to see the difference between both files.
save in a file all courses which has module=5:
SELECT DISTINCT fullname
FROM mdl_course
LEFT JOIN mdl_course_modules
ON mdl_course.id=mdl_course_modules.course
WHERE mdl_course_modules.module=5
into outfile '/tmp/forum';
save in file all courses which has module!=5:
SELECT DISTINCT fullname
FROM mdl_course
LEFT JOIN mdl_course_modules
ON mdl_course.id=mdl_course_modules.course
WHERE mdl_course_modules.module!=5
into outfile '/tmp/plus_forum';
Then, execute the difference:
$ diff forum plus_forum
But I'd like to return all courses which has only module=5 in only one query. Is it possible?
To make it simple let just solve the mdl_course_modules
SELECT course
FROM mdl_course_modules
GROUP BY course
HAVING SUM(module <> 5) = 0
AND SUM(module = 5) = 1 -- or >= 1
You can use a not in subquery to do this:
SELECT DISTINCT fullname
FROM mdl_course
LEFT JOIN mdl_course_modules
ON mdl_course.id=mdl_course_modules.course
WHERE mdl_course_modules.module=5
AND course.id not in (SELECT course
FROM mdl_course_modules
WHERE module <> 5)
One way to do this is to use the exists predicate with a correlated subquery.
select *
from mdl_course_modules t
where not exists (
select 1
from mdl_course_modules
where t.course = course -- reference the outer table
and module <> 5 -- and find rows that have any other module than 5
)
Sample SQL Fiddle
Since it's not completely clear what data is in what table you'll have to adjust the table and column names to suit your setup, but the concept should be clear.

MySQL Filtering rows from three tables

Let's say i've got this database:
book
| idBook | name |
|--------|----------|
| 1 |Book#1 |
category
| idCateg| category |
|--------|----------|
| 1 |Adventures|
| 2 |Science F.|
book_categ
| id | idBook | idCateg | DATA |
|--------|--------|----------|--------|
| 1 | 1 | 1 | (null) |
| 2 | 1 | 2 | (null) |
I'm trying to select only the books which are in category 1 AND category 2
This is what I've got so far:
SELECT book.* FROM book,book_categ
WHERE book_categ.idCateg = 1 AND book_categ.idCateg = 2
Obviously, this giving 0 results becouse each row has only one idCateg it does work width OR but the results are not what I need. I've also tried to use a join, but I just can't get the results I expect.
Here it's the SQLFiddle of my current project, the data at the begining is just a sample.
SQLFiddle
Any help will be really appreciated.
You could double join with a constraint on the category id:
SELECT a.* FROM book AS a
INNER JOIN book_categ AS b ON a.idBook = b.idBook AND b.idCateg = 1
INNER JOIN book_categ AS c ON a.idBook = c.idBook AND c.idCateg = 2
You could use a subquery:
SELECT a.* FROM book AS a
WHERE
(SELECT COUNT(DISTINCT idCateg) FROM book_categ AS b
WHERE b.idBook = a.idBook AND b.idCateg IN (1,2)) = 2
If you are on MySQL as your fiddle implies, you should prefer the join variant, since most joins are much faster in MySQL than subqueries.
edit
This one should also work:
SELECT a.* FROM book a
INNER JOIN book_categ AS b ON a.idBook = b.idCateg
WHERE b.idCateg IN (5, 6)
GROUP BY idBook
HAVING COUNT(DISTINCT b.idCateg) = 2
and should be faster than the two above, although you have to change the last number according to the number of category ids you are requesting.

Select a value in a first table according to another value of a second table (sql)

let me explain my situation, it really clearer than the title! I have two tables. Let give a look here and than I will you explain what I would like to do.
First table (lesson table)
+------------------+----------------+
| LessonCode | SubjectCode |
+------------------+----------------+
| 1 | 10 |
| 2 | 11 |
| 3 | 12 |
+------------------+----------------+
Second table (subject table)
+------------------+----------------+------------+
| subjectCode | SubjectName | teacherCode|
+------------------+----------------+------------+
| 10 | Maths | 15 |
| 11 | English | 20 |
| 12 | Greek | 30 |
+------------------+----------------+------------+
I would select from table lesson the subject that has teacherCode=20. It is possible in one query?
To get all lessons of teacher X, you will have to join both tables:
select LessonCode from lesson l
inner join subject s on s.subjectCode = l.SubjectCode
where s.teacherCode = x
This basically does the following: It creates the cross product of the two tables and then deletes all lines which do not comply with the on clause. Then it deletes all lines which do not comply with the where clause. This leaves only lessons of a given teacher X.
Try this:
select *
from lesson l
join subject s on s.subjectCode=l.SubjectCode
where s.teacherCode=20
You need to use a simple join.
select l.*
from lesson l
join subject s on l.SubjectCode=s.SubjectCode
where s.teacherCode=20
SELECT
*
FROM
(lesson, subject)
WHERE
lesson.SubjectCode = subject.subjectCode AND
subject.teacherCode = 20
SELECT SubjectCode
from LessonTbl lt
Left Outer join subjectTbl st
on lt.subjectCode = st.subjectCode
where st.teacherCode=20.
SELECT A.*
FROM lesson A
JOIN subject B ON A.SubjectCode = B.SubjectCode
WHERE B.teacherCode = '20'
Select a.*
From Lesson a
Inner Join Subject b on a.SubjectCode = b.SubjectCode
where c.TeacherCode = '20'
That's all. As long as you know that every Lesson's SubjectCode exists in the Subject table, just do an Inner Join like in my example. Otherwise, change it to a Left Outer Join.

How to do this query in MySQL which one should I use using left join or right join or inner join?

table book:
BookCode| AuthorShortN |Title
============================================
101 | Anton B | THe Book of Leaves
102 | JJ. Abram | Wish Upon A Star
103 | Anonymous | Secret of Universe
104 | Anton B | The Sentinel
table author:
AuthorID|AuthorFullName |Nationality
=====================================
A01 | Anton Balwin | USA
J02 | Johannes J Abram| UK
table bookauthor:
BookCode|AuthorID
=================
101 | A01
102 | J02
103 | X01
104 | A01
I have three table with the structure look like this. And I would like to have a query such that the result will be:
if I do this query
select *
from book tb , author ta, bookauthor tba
where tb.BookCode = tba.BookCode and tba.AuthorID = ta.AuthorID
It will not show row 103 | Anonymous | Secret of Universe as the Author is not in the table author.
and what I want is:
BookCode| Title | AuthorID | AuthorShortN
===========================================================
101 | THe Book of Leaves|A01 | Anton Balwin
102 | Wish Upon A Star |J02 | Johannes J Abram
103 | Secret of Universe|NULL | Anonymous
104 | The Sentinel |A01 | Anton Balwin
how to fix the query to produce such result ?
Thanks very much for the help.
You are looking for a left join on the table you allow nulls in:
SELECT tb.BookCode, tb.Title, ta.AuthorID, tb.AuthorShortN
FROM book AS tb
INNER JOIN bookauthor AS tba ON tba.BookCode=tb.BookCode
LEFT JOIN author AS ta ON tba.AuthorID=ta.AuthorID
Note your example correct output looks for a null in AuthorShortN and you actually have Anonymous in the data. The inner join to BookAuthor assumes there are entries in this table even when the author is unknown, as it looks in your data.
Left Join will give all results from left table whether or not there are corresponding entries in the right table
SELECT *
FROM book tb
LEFT JOIN author ta ON tb.BookCode = ta.AuthorID
LEFT JOIN bookauthor tba ON ta.AuthorID = tba.BookCode;
Also, Off topic of the question - shouldn't the AuthorShortN field be in the author table?