Tamil Nadu HSE Second Year Computer Applications study materials
Tamil Nadu HSE Second Year Computer Applications study resources

The Library Query That Returns 13,500 Rows

Tamil Nadu HSE Second Year Computer Applications · Put your knowledge to work in context.

All case studies

The Library Query That Returns 13,500 Rows

A higher secondary school in Salem computerises its library. The database has three tables: Members(member_id, member_name, class), Books(book_id, title, category), Loans(loan_id, member_id, book_id, issue_date, due_date, return_date). There are 300 members and 1,200 books. The librarian runs SELECT COUNT(*) FROM Loans WHERE return_date = NULL; and gets 0, although 45 loans are still outstanding. A second query, SELECT member_name, title FROM Members, Books, Loans WHERE return_date IS NULL; returns 13,500 rows. The librarian also notices that when a member changes class, staff must update many rows because class is stored in Loans as well as Members. In Loans, member_name and book_title are also stored. Due dates are 14 days after issue. Today is 2025-02-10. The librarian wants an overdue list: member name, class, book title and days overdue for loans not yet returned.

1. Explain why the first query returns 0 and the second returns 13,500 rows. Rewrite the count correctly for outstanding loans.

Read the worked answer

In SQL, NULL is not a value but a marker for 'unknown'. Any comparison with NULL yields UNKNOWN, and WHERE keeps only rows for which the condition is TRUE. Therefore return_date = NULL is never TRUE, even for rows where return_date is NULL; COUNT() counts zero such rows. The correct predicate is return_date IS NULL. The 13,500 figure is 300 × 45: the FROM clause lists Members, Books and Loans with no join conditions, so every member row is paired with every book row and every outstanding loan row - a Cartesian product. The WHERE clause filters to the 45 outstanding loans but does not connect member_id or book_id, so each of the 300 members appears with each of the 45 loans. Correct count: SELECT COUNT() FROM Loans WHERE return_date IS NULL; and for a joined list, add JOIN ... ON Loans.member_id = Members.member_id AND Loans.book_id = Books.book_id.

2. Write a query returning member name, class, book title and days overdue for loans not returned and due before 2025-02-10. State any assumptions.

Read the worked answer

SELECT m.member_name, m.class, b.title, DATEDIFF('2025-02-10', l.due_date) AS days_overdue FROM Loans l JOIN Members m ON l.member_id = m.member_id JOIN Books b ON l.book_id = b.book_id WHERE l.return_date IS NULL AND l.due_date < '2025-02-10' ORDER BY days_overdue DESC; The join conditions are essential; without them the result is a Cartesian product. return_date IS NULL excludes returned copies, and due_date < date excludes loans due today, which are not yet overdue. DATEDIFF(expr1, expr2) in MySQL returns expr1 − expr2 in days, so the later date goes first. In standard SQL or SQLite, use date subtraction or CURRENT_DATE, and if 'today' is dynamic replace the literal with CURRENT_DATE. The query assumes one loan row per physical copy and that due_date is never NULL; if it can be NULL, add due_date IS NOT NULL. It also assumes a book can have multiple loan records over time.

3. The librarian stores member_name, class and book_title in Loans as well as in Members and Books. Identify the anomalies and propose a revised schema.

Read the worked answer

Storing member_name and class in Loans repeats data already in Members; class is functionally dependent on member_id, not on loan_id, so the table is not in 3NF. Storing book_title repeats data from Books; title depends on book_id. Update anomaly: when a member changes class, staff must update every loan row, and any missed row leaves conflicting class values. Insertion anomaly: a new member or book cannot be recorded until a loan exists if the loan table is the only place with the details. Deletion anomaly: deleting the last loan can erase the only record of a member or book. Revised: Members(member_id PK, member_name, class), Books(book_id PK, title, category), Loans(loan_id PK, member_id FK, book_id FK, issue_date, due_date, return_date). Foreign keys enforce referential integrity, and a member's class is stored once. If a book can have multiple copies, add copy_id and make Loans reference the copy. The rule is that each fact should be stored in one place.