Querying with SQL · 用 SQL 查询
| English | 中文 | Pinyin · 拼音 |
|---|---|---|
| SQL/ˌes kjuː ˈel/ | 结构化查询语言 | jié gòu huà chá xún yǔ yán |
| JOIN/dʒɔɪn/ | 连接 | lián jiē |
| GROUP BY/ɡruːp baɪ/ | 分组 | fēn zǔ |
Two different courses share a title
- Two courses are both called Robotics. Grouping only by title combines their enrolments and hides that they are different courses.
- SQL 结构化查询语言 describes the data result you want. Check row identity and expected output before trusting a plausible count.
Follow the relationship in the join
- A JOIN 连接 combines rows using a relationship such as
e.course_id = c.id. Write the intended relationship explicitly. - A cross join pairs every row on one side with every row on the other. In SQLite, an unconstrained join can produce that product; other SQL systems can reject missing join conditions.
In SQLite, an unconstrained join pairs three courses with three enrolments. How many pairs can it produce?
A cross product has 3 × 3 rows, before any later filtering.
Keep zero-enrolment courses
- A left join keeps every course, including one without a matching enrolment. Its unmatched enrolment fields are null.
- Count
e.student_id, which excludes null, rather thanCOUNT(*), which also counts the retained unmatched row. The empty course should report zero.
Which expression correctly counts zero enrolments for an unmatched left-joined course?
COUNT of the unmatched nullable field excludes null; COUNT(*) counts the retained row.
Run a query with known answers
- Run this complete script in a local SQLite database. Its two Robotics courses have different IDs, and Art has no enrolments.
- GROUP BY 分组 groups by both course ID and title. Expected rows are
(7, Robotics, 1),(8, Robotics, 2)and(9, Art, 0).
CREATE TABLE courses (id INTEGER PRIMARY KEY, title TEXT NOT NULL);
CREATE TABLE enrolments (student_id INTEGER, course_id INTEGER);
INSERT INTO courses VALUES (7, 'Robotics'), (8, 'Robotics'), (9, 'Art');
INSERT INTO enrolments VALUES (1, 7), (1, 8), (2, 8);
SELECT c.id, c.title, COUNT(e.student_id) AS enrolled
FROM courses AS c
LEFT JOIN enrolments AS e ON e.course_id = c.id
GROUP BY c.id, c.title
ORDER BY c.id;
Complete the clause that groups by course identity and title: ____ c.id, c.title
GROUP BY defines the groups. Including the ID keeps different same-title courses separate.
Which enrolment counts does the complete query return for course IDs 7, 8 and 9?
The sample has one match for 7, two for 8 and none for 9.
Filter rows and groups at different stages
WHEREfilters input rows before grouping.HAVINGfilters groups using a condition such asCOUNT(e.student_id) >= 2.- In this example, adding that HAVING condition before ORDER BY returns only course 8. Filtering
e.student_idin WHERE can remove the unmatched rows you meant to retain.
Which clause filters groups to those with at least two enrolled students?
HAVING applies a condition to groups; WHERE filters input rows.
Explain WHERE and HAVING using the course-count example.
WHERE filters rows; HAVING tests each group’s count.
Use edge cases to verify the result
- Check repeated titles, zero matches and multiple matches against known counts. A result that looks reasonable is not enough.
- Explain the selected fields, join condition, grouping and count. Decide whether duplicate relationship rows are valid or should be prevented by the schema.
Join on the relationship, group by the identity, and count the intended thing. A tiny known dataset makes incorrect queries easier to see.
A plausible count is sufficient evidence that a SQL query is correct.
Compare known expected rows, including zero matches and repeated titles.
Grouping only by title keeps the two Robotics courses separate.
Equal titles form one group. Group by the course identity as well.