Skip to content
experience

Teaching SQL joins to Class 12 with the attendance register and the fee register

Anitha Joseph@anitha_miss

October 5, 2026 · 3 min read

Every year my Class 12 children memorise "INNER JOIN returns only matching rows" for the exam, write it perfectly, and understand nothing. This year I tried something different and it worked better than I expected, so I am sharing.

I borrowed two real registers from the office: the attendance register (roll number, name) and the fee register (roll number, term, amount). I asked the children: "Who has paid fees, with their names?" They had to look in one book, find the roll number, then look in the other book. That is a join. They did it with their fingers before they ever typed it.

Then we made the same thing in SQL (names changed, the children chose them):

CREATE TABLE students (roll_no INT PRIMARY KEY, name VARCHAR(40));
CREATE TABLE fees (roll_no INT, term INT, amount INT);

INSERT INTO students VALUES (1, 'Aleena'), (2, 'Farhan'), (3, 'Gokul'), (4, 'Diya');
INSERT INTO fees VALUES (1, 1, 2500), (2, 1, 2500), (2, 2, 2500), (5, 1, 2500);

-- who has paid, with names
SELECT s.name, f.term, f.amount
FROM students s
INNER JOIN fees f ON f.roll_no = s.roll_no;

-- every student, paid or not
SELECT s.name, f.term
FROM students s
LEFT JOIN fees f ON f.roll_no = s.roll_no;

-- who has not paid anything (the office's favourite query)
SELECT s.name
FROM students s
LEFT JOIN fees f ON f.roll_no = s.roll_no
WHERE f.roll_no IS NULL;

Three moments that taught them more than my notes ever did:

  • "Miss, why is Farhan coming two times?" Because Farhan paid two terms. One student, many fee rows. One-to-many, explained by Farhan, who was very proud.
  • Roll number 5 appears nowhere. There is a fee row for roll 5 but no student 5. A student who transferred out last year. The inner join hides him, the left join from students also hides him. So we talked about RIGHT JOIN, and about what happens when data in two registers does not agree. The office clerk was very interested in this part.
  • Gokul and Diya with NULL. In the LEFT JOIN they come with an empty term. "NULL means the book had nothing, not zero." This one finally made sense to them.

And of course one boy asked if he can delete his row from the fees table. I told him only if he deletes himself from the students table also. Referential integrity, explained. Ayyo, the laughter.

Next week, GROUP BY with the same registers: total collected per term. If anyone has a good real-world example for HAVING that sixteen year olds will care about, kindly share.

Get the best of #select-star-anonymous weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.

Comments

10

Sign in to join the conversation.

Sign in to comment
Lakshmi Prasad@lakshmi_teaches_py1 rep in SELECT * Anonymous
Respected Anitha madam, this is wonderful. I am a maths teacher just starting Python and SQL with Class 9 and 10. May I use the fee register example in my class? Farhan appearing two times is a very good way to explain one-to-many. Thanking you.
4 net votes
Anitha Joseph@anitha_miss#5 in SELECT * Anonymous
Of course, Lakshmi, please use it. Sheri, change the names to your children's names, they love seeing themselves in the output 😄
5 net votes
Rhys Llewellyn@rhys_teaches_code2 rep in SELECT * Anonymous
Diolch Anitha, this is tidy. I do something similar with the register and the dinner money list. The transferred student is a brilliant way to get to data quality. Small task for anyone reading: write the query that finds fee rows with no matching student. Answers below 😄
5 net votes
Meenal Deshpande@meenal_restarts1 rep in SELECT * Anonymous
SELECT f.roll_no, f.amount FROM fees f LEFT JOIN students s ON s.roll_no = f.roll_no WHERE s.roll_no IS NULL; Did I pass, sir? 🙂
2 net votes
Rhys Llewellyn@rhys_teaches_code2 rep in SELECT * Anonymous
Full marks, Meenal! And you flipped the LEFT JOIN instead of writing a RIGHT JOIN, which is what most people do in real life too.
3 net votes
Nikhil Sharan@nikhil_twopointers1 rep in SELECT * Anonymous
Anitha miss, this is how it should be taught. Dry run with real registers first, then the query. Samjhe? The children will remember Farhan longer than any definition.
2 net votes
Nurul Aisyah@nurul_sql#8 in SELECT * Anonymous
the 'who has not paid' query is literally what my bank's finance team asks me every Friday 5pm lah. for HAVING: 'which class collected less than 80% of the fees this term'. confirm the students will care when it's their class
3 net votes
Anitha Joseph@anitha_miss#5 in SELECT * Anonymous
Nurul, that is perfect. Class against class, they will fight for it 😄 Thank you.
1 net votes
Aman Raj@kota_coder_171 rep in SELECT * Anonymous
anitha didi ye bahut accha hai!! 12th mein SQL aayega kya humko?? abhi toh physics padh raha hu 😅
2 net votes
Anitha Joseph@anitha_miss#5 in SELECT * Anonymous
Aman, if you are in CBSE, yes, SQL is in Class 12 Computer Science. But first finish your physics, then SQL. Teacher's orders 😄
3 net votes