I am trying to select whether or not an entry exists in another table. Here's a simple example:
Two tables:
Student
ID Major
1 CS
2 CS
3 CS
4 CS
Student_Teacher
SID TID
1 A
1 B
1 C
3 B
3 D
The first table has a list of student IDs (key = Student ID)
The 2nd table has a list of student -> teachers (key = Student ID, Teacher ID combination).
I would like to select ALL students (1,2,3,4; one in each row) and a flag for whether or not they have a teacher.
SELECTED:
ID Flag
1 1
2 0
3 1
4 0
I know this is possible to do using group by:
select Student.ID, count(Student_Teacher.TID)
from Student left join Student_Teacher
group by Student.ID
Is there a simpler way?
You can try joining to a derived table that contains the distinct student id values of the second table:
SELECT ID, IF(ST.SID IS NOT NULL, 1, 0) AS FLAG
FROM Student AS S
LEFT JOIN (
SELECT DISTINCT SID
FROM Student_Teacher
) AS ST ON S.ID = ST.SID
Related
Table Student
StudentID
StudentName
1
A
2
B
3
C
Table Book
BookID
BookName
1
Book1
2
Book2
3
Book3
Table BookAssignment
AssignID
BookID
StudentID
DateTime
1
1
1
2021-06-26
2
2
1
2021-07-01
3
1
2
2021-07-03
The result table should be
StudentID
StudentName
BookCount
1
A
2
2
B
1
3
C
0
How to get the result table in one SQL execution?
Left JOIN seems not an option since it eliminates StudentID 3
Just added another DateTime column to the BookAssignment table - What is SQL syntax to query the book count over the last 7 consecutive days (even for 0 book for day count)?
you need to use simple group by using left join between two tables:
select s.StudentID, s.StudentName , count(*) BookCount
from students s
left join books b
on s.StudentID = b.StudentID
group by s.StudentID, s.StudentName
I'd left join the student table on an aggregate query of the books and use coalesce to fill in the zeros:
SELECT s.StudentID, StudentName, COALESCE(cnt, 0)
FROM student s
LEFT JOIN (SELECT StudentID, COUNT(*) AS cnt
FROM books
GROUP BY StudentID) b ON s.StudentID = b.StudentID
You can also use a correlated subquery:
select s.*,
(select count(*)
from books b
where s.StudentID = b.StudentID
) as bookCount
from students s;
This has some advantages over using a join/group by approach:
You can trivially include all columns in the select. They don't have to repeated in the group by.
With an index on books(StudentID) this often has the best performance.
This avoids the outer aggregation, which can kill performance.
Adding another dimension (say the number of courses the student has) just works, without worrying about Cartesian Products.
select s.StudentID, s.StudentName ,(select count(*) from BookAssignment b where b.studentid = s.studentid) as BookCount
from students s
take for example that I have an instructors, subjects, and instructor_subject table.
instructors
-----------
1
2
subjects
--------
1
2
3
instructor_subject
--------------------------
instructor_id | subject_id
1 | 1
1 | 2
Notice that instructor 1 has 2 subjects. Now how do I go about selecting from the pivot table the subjects that instructor 1 doesn't have (i.e instructor 1 and subject 3). While also being able to retrieve other columns from instructors table and subjects table. The other columns being the instructor name, subject name and so on.
You can use cross join to get all the combinations of instructors and subjects and then filter out the ones that don't match:
select i.*, s.*
from instructors i cross join
subjects s left join
instructor_subject si
on si.instructor_id = i.instructor_id and si.subject_id = s.subject_id
where si.instructor_id is null;
I have two tables one is student and the other is class:
The first table has the following columns id, marks, classid, studentname
the data of first table is as follow:
id 1 2 3 4
marks 200 250 300 298
classid 2 2 1 3
studentname Vikas Anil Ravil Rahul
The other table has the following columns id, classname
The data of the other table is as follow:
id 1 2 3 4
classname BCA MCA BA BCA
now the question is that
how to get the name of student and class name having the maximum marks.
how to get the name of student and class name having the minimum marks.
how to get the name of the class having maximum students.
Pls Guys help me I'm new with MySQL.
SELECT a.name, b.classname
FROM student a
LEFT JOIN class b
ON a.classid = b.id
WHERE a.marks = (SELECT MAX(marks) FROM student);
SELECT a.name, b.classname
FROM student a LEFT JOIN class b
ON a.classid = b.id
WHERE a.marks = (SELECT MIN(marks) FROM student);
SELECT b.classname
FROM student a
LEFT JOIN class b
ON a.classid = b.id
ORDER BY COUNT(a.classid) DESC LIMIT 1;
not sure but you can try this...im just a newbie too...
I am planning to create a website similar to IMDB.com. To reduce execution time I am using the following structure. Is it okay for faster working?
Table - 1
Id Movie_name description
1 name one some description
2 name two some description
3 name three some description
Table 2
id actorname
1 name 1
2 name 2
3 name 3
4 name 4
Table 3
id movieid actorid
1 1 1
2 1 2
3 1 3
4 1 9
5 2 6
6 2 5
7 2 8
8 2 1
When I want to list actors in a movie program will retrieve actors ids from table 3 and find respective names from table 2 (using single query). When I want to list the movies of a actor it will retrieve movie ids from table 3 and find respective names from first table. Will it work properly? Any other ideas?
This will give all actors in a specified movie,
SELECT c.ID, c.actorName
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE a.ID = 1
This one will give all movies for a specified actor
SELECT a.*
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID = 1
SQLFiddle Demo (both queries)
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
UPDATE 1
This is called Relational Division
SELECT a.ID, a.Movie_Name
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID IN (1, 2, 3)
GROUP BY a.ID, a.Movie_Name
HAVING COUNT(DISTINCT c.ID) = 3
SQL of Relational Division
I suggest that you modify table3 by taking away the id field. Use the movieid and actorid together as your primary key. You might want to add other fields to this table such as name of character and order of appearance as suggested in the comment by Jermaine Xu.
Example database :
ID StudentName StudentClass
1 John A
2 John B
3 Peter A
4 John A
5 John B
I want the result should be
ID StudentName StudentClass
1 John A
2 John B
3 Peter A
Statment
DELETE FROM Student
WHERE ID NOT IN (SELECT *
FROM (SELECT MIN(n.ID)
FROM Student n
GROUP BY n.StudentName) x)
How do I keep John name on class A & B?
DELETE a FROM Student a
LEFT JOIN
(
SELECT MIN(ID) AS minid
FROM Student
GROUP BY StudentName, StudentClass
) b ON a.id = b.minid
WHERE
b.minid IS NULL
A better method to disallow even insertion of such duplicates would be multi-column unique index(it will optimize your searches too). Here is how:
ALTER TABLE `Student`
ADD UNIQUE INDEX `idx` (`StudentName`, `StudentClass`)
You should be able to join Students against itself, with a JOIN predicate that ensures the JOIN matches duplicate students, and delete the join'd row:
DELETE
duplicate_students.*
FROM Students JOIN Students as duplicate_students
ON Students.StudentName = duplicate_students.StudentName
AND Students.StudentClass = duplicate_students.StudentClass
AND duplicate_students.ID > Students.ID
NOTE: Please back up your data first; I take no responsibility for lost data :-) This is a conceptual idea and has not been tested.
This should work:
DELETE S FROM Student S
INNER JOIN(
SELECT MIN(ID) AS ID,StudentName,StudentClass FROM Student
GROUP BY StudentName,StudentClass
) S2 ON S.ID != S2.ID AND S.StudentName = S2.StudentName AND S.StudentClass = S2.StudentClass
Its basically selecting the minimum ID out of all the duplicate records in sub query. Then we simply delete everything that matches that Class and Name, But we don't match the Minimum Id, so at end of day, we are keeping (presumably) 1st record out of duplicates and eradicating rest.