Students Who Attended Every Fest Workshop — SQL Medium Problem

At the college tech fest, students check in to workshops by scanning a QR code at the door.

  • Difficulty: Medium
  • Topics: Aggregation, Subqueries
  • Dialect: MySQL
  • Problem: #22

Problem statement

At the college tech fest, students check in to workshops by scanning a QR code at the door. A student who steps out and comes back scans again, so the same student and workshop can appear more than once.

Return the roll_no of every student who checked in to every workshop listed in Workshop. Return the rows in any order.

Tables

Table: Workshop

ColumnType
workshop_idint
topicvarchar

Primary key: workshop_id.

One row per workshop at the fest.

Table: CheckIn

ColumnType
scan_idint
roll_noint
workshop_idint
scanned_atdatetime

Primary key: scan_id.

One row per QR scan. Every workshop_id here is in Workshop.

Examples

Example 1

Workshop

workshop_idtopic
1Git basics
2Intro to Docker
3Figma for devs

CheckIn

scan_idroll_noworkshop_idscanned_at
150112025-02-14 10:02:11
250122025-02-14 12:00:40
350212025-02-14 10:05:03
450212025-02-14 11:15:47
550222025-02-14 12:01:30
650132025-02-15 09:58:00
750312025-02-14 10:10:10
850322025-02-14 12:04:22
950332025-02-15 10:01:05

Output

roll_no
501
503

How to solve Students Who Attended Every Fest Workshop

"Attended every workshop" is relational division, and the counting form is the easiest to write. Group the scans by student; the student qualifies when the number of different workshops they scanned into equals the number of workshops in the catalogue, which a scalar subquery (SELECT COUNT(*) FROM Workshop) supplies.

DISTINCT is essential. Student 502 in the example scanned three times but into only two workshops; COUNT(*) = 3 would wrongly let them through. Counting distinct ids can only match the total when every workshop is covered, because every workshop_id in CheckIn is a real workshop — without that guarantee you would have to join to Workshop first so that unknown ids could not stand in for missing ones.

The double NOT EXISTS is the textbook form: keep a student for whom there is no workshop with no matching scan. It reads like the definition and needs no counting, so duplicates never matter. The third query builds every student × workshop pair with a CROSS JOIN, attaches scans with a LEFT JOIN, and keeps students with no missing pair.

The grouped version reads CheckIn once and Workshop once; the NOT EXISTS form probes CheckIn once per student and workshop, which is fast with an index on (roll_no, workshop_id).

Reference solution (MySQL)

SELECT roll_no
FROM CheckIn
GROUP BY roll_no
HAVING COUNT(DISTINCT workshop_id) = (SELECT COUNT(*) FROM Workshop)

Another way

SELECT DISTINCT c.roll_no FROM CheckIn c
WHERE NOT EXISTS (
  SELECT 1 FROM Workshop w
  WHERE NOT EXISTS (SELECT 1 FROM CheckIn x WHERE x.roll_no = c.roll_no AND x.workshop_id = w.workshop_id)
)

Another way

SELECT s.roll_no
FROM (SELECT DISTINCT roll_no FROM CheckIn) s
CROSS JOIN Workshop w
LEFT JOIN CheckIn c ON c.roll_no = s.roll_no AND c.workshop_id = w.workshop_id
GROUP BY s.roll_no
HAVING SUM(c.scan_id IS NULL) = 0

← Share of Quiz Players Who Returned the Next Day · Monthly Ticket Refund Report by Railway Zone →