'SQL Server - Combine two select queries
I have two tables, Semester1 and Semester2. Semester1:
StudentId | SubjectId |
---|---|
abc | sub1 |
def | sub1 |
ghi | sub1 |
Semester2:
StudentId | SubjectId |
---|---|
abc | changedSub1 |
def | sub1 |
ghi | changedSub2 |
newStudent1 | sub2 |
newStudent2 | sub3 |
I am trying to write a single Select statement such that it selects rows from Semester2 that have:
- New StudentIds - i.e., StudentIds in Semester2 that are not in Semester1. So the result from this requirement should be Semester2's
newStudent1
andnewStudent2
rows.
AND
- Changed SubjectIds - i.e., SubjectId are different for the same StudentId between Semester1 and Semester2. So the result from this requirement should be Semester2's
changedSub1
andchangedSub2
rows.
I have been able to write two separate queries to select the 2 requirements separately:
-- Part 1
SELECT * FROM Semester2
WHERE StudentId NOT IN ( SELECT StudentId from Semester1 );
-- Part 2
SELECT Semester2.StudentId, Semester2.SubjectId
FROM Semester2
JOIN Semester1
ON (Semester1.StudentId = Semester2.StudentId)
WHERE Semester1.SubjectId <> Semester2.SubjectId;
How can I combine the two queries? Or if there is a better/easier/clearer way to write both requirements as a single query (without combining my above queries), how do I do that?
Solution 1:[1]
It looks like a single query with an outer join should suffice
select s2.*
from semester2 s2
left join semester1 s1 on s1.studentId = s2.studentId
where s1.studentId is null or s2.SubjectId != s1.SubjectId;
Solution 2:[2]
You could also do it in a single query using a join if UNION doesn't count for "single query":
SELECT s2.*
FROM Semester2 s2
LEFT OUTER JOIN Semester1 s1
ON s2.StudentId = s1.StudentId
AND s2.SubjectId = s1.SubjectId
WHERE s1.StudentId IS NULL;
The WHERE clause will make it so only results where there isn't a perfect match in Semester1 appear.
Solution 3:[3]
You might just need to extend your "Part 1" query a little. Right now it excludes all students from semester 1, but you only want to exclude students from semester 1 that do not have changed subjects in semester 2.
Something like this:
SELECT * FROM Semester2
WHERE StudentId NOT IN (-- Student ids with same subject from semester 1
SELECT StudentId FROM Semester1
WHERE Semester1.SubjectId = Semester2.SubjectId);
But I haven't tested it. Please let me know if I made some terrible mistake.
Solution 4:[4]
One option that requires no UNION
(which requires scanning the table twice) and no OR
condition (which can be slow) and no LEFT JOIN
(which confuses the optimizer into thinking there will be multiple joined rows)
SELECT s2.*
FROM semester2 s
WHERE NOT EXISTS (SELECT 1
FROM semester1 s1
WHERE s1.studentId = s2.studentId
AND s2.SubjectId = s1.SubjectId
);
Solution 5:[5]
Here's the simplest thing I can think of.
select Semester2.*
from Semester2
left outer join Semester1
on Semester1.StudentId = Semester2.StudentId
where NULLIF(Semester2.SubjectId,Semester1.SubjectId) is NOT NULL
NULLIF will return NULL if the two things are equal (same student had the same subject both semesters). Otherwise it returns Semester2.SubjectId. This excludes exactly what you want to exclude - students from Semester1 who didn't have a different subject in Semester2.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Stu |
Solution 2 | Bruce |
Solution 3 | Bart Hofland |
Solution 4 | Charlieface |
Solution 5 | J S |