Click here to Skip to main content
15,885,032 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have following type of tables


DECLARE @tbStudent TABLE (StudentId INT, StudentName NVARCHAR(100))
INSERT INTO @tbStudent (StudentId , StudentName)
VALUES (101,'James'),(102,'Smith'),(103,'Jackson'),(104,'Peter');

DECLARE @tbStudentCourseDetails TABLE (StudentId INT, CourseId INT)
INSERT INTO @tbStudentCourseDetails (StudentId , CourseId)
VALUES (101,1),(101,3),(101,6),
(102,4),(102,3),
(103,5),(103,3),
(104,1),(104,3),
(105,1);


DECLARE @tbCourseDone TABLE (CourseId INT)
INSERT INTO @tbCourseDone(CourseId)
VALUES (1),(3);

SELECT * FROM @tbStudent
SELECT * FROM @tbStudentCourseDetails
SELECT * FROM @tbCourseDone


Now i need to get the StudentId, StudentName,CourseId records where Student has done all the courses defined in @tbCourseDone table i.e. 1 and 3

Output should be
StudentId StudentName CourseId
101 James 1
101 James 3
104 Peter 1
104 Peter 3

What I have tried:

I tried In operator but it is fetching the records of the student where any course is matched

I also tried below query and got the result i want:

DECLARE @RecCount int=(SELECT count(*) FROM @tbCourseDone)

;WITH myCTE
AS
(
SELECT EM.StudentId
FROM @tbStudent EM
INNER JOIN @tbStudentCourseDetails teld ON EM.StudentId = teld.StudentId
INNER JOIN @tbCourseDone t ON t.CourseId=teld.CourseId
GROUP BY EM.StudentId HAVING COUNT(Em.StudentId)=@RecCount
)

SELECT EM.StudentId,StudentName,teld.CourseId
FROM @tbStudent EM
INNER JOIN @tbStudentCourseDetails teld ON EM.StudentId = teld.StudentId
INNER JOIN @tbCourseDone t ON t.CourseId=teld.CourseId
INNER JOIN myCTE cte ON cte.StudentId=EM.StudentId


But it is not optimized query and can be shorten i think. Please help me in getting this result.
Posted
Updated 29-May-19 3:59am
v4

1 solution

There might be a simpler way to do this, but the first thing that comes to mind is a double NOT EXISTS test:
SQL
SELECT
    S.StudentId,
    S.StudentName,
    C.CourseId
FROM
    @tbStudent As S
    INNER JOIN @tbStudentCourseDetails As C
    ON C.StudentId = S.StudentId
WHERE
    -- Only return details for the required courses:
    Exists
    (
        SELECT 1
        FROM @tbCourseDone As D
        WHERE D.CourseId = C.CourseId
    )
And
    -- Exclude students who haven't done all required courses:
    Not Exists
    (
        SELECT 1
        FROM @tbCourseDone As D
        WHERE Not Exists
        (
            SELECT 1
            FROM @tbStudentCourseDetails As C2
            WHERE C2.CourseId = D.CourseId
            And C2.StudentId = S.StudentId
        )
    )
ORDER BY
    S.StudentId,
    C.CourseId
;
 
Share this answer
 
Comments
Webcodeexpert.com 30-May-19 5:17am    
Thanks for your solution. It worked well. But i feel your and my query can be short. I don't know how. I am waiting for some other solutions.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900