CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71);
SELECT * FROM student;
表存储记录:每一行是一条记录,每一列是一个字段
每一行(row)是一条记录(record)。按习惯,SQL 关键字写成大写。
一条语句以分号 ; 结尾。
1.2
选择列
English
List the columns 列 you want, separated by commas. Use AS to rename a column in the result (an alias 别名).
A selected column can also be a calculation — pair it with AS to name the new column:
SELECT DISTINCT col removes duplicate values from the result.
中文
把你想要的列(column)列出来,用逗号分隔。用 AS 在结果里给列重命名(一个别名(alias))。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71);
SELECT name, score AS mark FROM student;
选中的列也可以是一个计算——配合 AS 给新列命名:
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71);
SELECT name, score + 5 AS bonus FROM student;
SELECT DISTINCT col 会去掉结果中的重复值。
1.3
用 WHERE 筛选
English
WHERE keeps only the rows that match a condition 条件. Compare with =, <> (not equal), <, >, <=, >=. Put text in single quotes.
SQL runs the parts in this order: FROM → WHERE → SELECT.
Common mistakes
Put text values in single quotes: WHERE name = 'Ann'; column names have no quotes.
SELECT * returns every column — name only the columns you need.
WHERE filters rows; it comes after FROM.
中文
WHERE 只保留符合条件(condition)的行。用 =、<>(不等于)、<、>、<=、>= 比较。文本要放在单引号里。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71), (3, 'Ana', 95);
SELECT name, score FROM student WHERE score >= 80;
CREATE TABLE student (id INTEGER, name TEXT, form TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei','11A',88),(2,'Sam','11B',71),(3,'Ana','11A',95);
SELECT name FROM student WHERE form = '11A' AND score >= 90;
AND needs all true; OR needs any; NOT flips one
2.2
LIKE、IN 与 BETWEEN
English
LIKE matches a text pattern 模式: % stands for any text and _ for one character — these are wildcards 通配符.
Pattern
Matches
'M%'
starts with M
'%a'
ends with a
'%an%'
contains "an"
'M_i'
M, then exactly one character, then i
IN matches a set 集合 of values; BETWEEN matches a range 范围 (both ends included).
中文
LIKE 匹配一个文本模式(pattern):% 代表任意文本,_ 代表一个字符——它们是通配符(wildcard)。
CREATE TABLE student (id INTEGER, name TEXT, form TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei','11A',88),(2,'Sam','11B',71),(3,'Ana','11A',95);
SELECT name FROM student WHERE name LIKE 'M%'; -- starts with M
模式
匹配
'M%'
以 M 开头
'%a'
以 a 结尾
'%an%'
包含 "an"
'M_i'
M,接恰好一个字符,再接 i
IN 匹配一个值的集合(set);BETWEEN 匹配一个范围(range)(两端都包含)。
CREATE TABLE student (id INTEGER, name TEXT, form TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei','11A',88),(2,'Sam','11B',71),(3,'Ana','11A',95);
SELECT name, score FROM student
WHERE form IN ('11A', '11C') AND score BETWEEN 80 AND 100;
2.3
NULL 空值
English
NULL marks a missing value 缺失值 — nothing was stored in that cell. NULL is not 0 and not an empty string. A comparison with = or <> never matches it; test with IS NULL or IS NOT NULL.
WHERE score = NULL returns no rows at all — not even Sam's row.
A NULL in arithmetic gives NULL: score + 5 stays NULL for Sam.
Common mistakes
Test for an empty value with IS NULL, never = NULL.
In LIKE, % matches any text and _ matches one character: 'A%' means "starts with A".
IN (1, 2, 3) is shorter than many ORs; BETWEEN a AND b includes both ends.
中文
NULL 表示缺失值(missing value)——这个单元格里什么都没存。NULL 不是 0,也不是空字符串。用 = 或 <> 的比较永远匹配不到它;要用 IS NULL 或 IS NOT NULL 来判断。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', NULL), (3, 'Ana', 95);
SELECT name FROM student WHERE score IS NULL;
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', NULL), (3, 'Ana', 95);
SELECT name, score FROM student WHERE score IS NOT NULL;
ORDER BY sorts 排序 the result rows. Add DESC for descending 降序 (high to low); the default is ascending 升序 (low to high).
Sort by more than one column
List several columns. A tie 平局 in the first column is broken by the next.
LIMIT (top-N)
LIMIT n keeps only the first n rows — pair it with ORDER BY for a top-N 前 N 名 list.
ORDER BY can also sort by an alias or a calculation: ORDER BY avg_score DESC.
Text sorts alphabetically: ORDER BY name runs A → Z.
Common mistakes
ORDER BY sorts ascending by default; add DESC for descending.
ORDER BY comes near the end, after WHERE and GROUP BY.
LIMIT caps how many rows come back, but only after sorting.
中文
ORDER BY 对结果行排序(sort)。加 DESC 表示降序(descending)(从高到低);默认是升序(ascending)(从低到高)。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei',88),(2,'Sam',71),(3,'Ana',95);
SELECT name, score FROM student ORDER BY score DESC;
按多列排序
列出多个列。第一列出现平局(tie)时,由下一列来决定先后。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei',88),(2,'Sam',88),(3,'Ana',95);
SELECT name, score FROM student ORDER BY score DESC, name ASC;
LIMIT(前 N 名)
LIMIT n 只保留前 n 行——配合 ORDER BY 就能得到一个前 N 名(top-N)列表。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei',88),(2,'Sam',71),(3,'Ana',95);
SELECT name, score FROM student ORDER BY score DESC LIMIT 2;
ORDER BY 也可以按别名或计算排序:ORDER BY avg_score DESC。
文本按字母顺序排序:ORDER BY name 从 A 到 Z。
常见错误
ORDER BY 默认升序;要降序加 DESC。
ORDER BY 写在靠后的位置,在 WHERE 和 GROUP BY 之后。
LIMIT 限制返回的行数,但要在排序之后才起作用。
ORDER BY sorts; LIMIT keeps the first n after sorting
CREATE TABLE student (id INTEGER, name TEXT, form TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei','11A',88),(2,'Sam','11B',71),(3,'Ana','11A',95);
SELECT COUNT(*), ROUND(AVG(score), 2), MAX(score) FROM student;
4.2
GROUP BY 与 HAVING
English
GROUP BY makes one summary row per group 组. HAVING filters those groups — it is like WHERE, but it runs after grouping.
Whatever order you write them in, SQL always runs the clauses of a query in the same fixed order:
Step
Clause
1
FROM (and any JOIN)
2
WHERE — filter rows
3
GROUP BY — form groups
4
HAVING — filter groups
5
SELECT — compute the output columns
6
ORDER BY, then LIMIT
Common mistakes
You cannot select a plain column beside an aggregate unless it is in GROUP BY.
Filter rows with WHERE (before grouping) and filter groups with HAVING (after).
COUNT(*) counts rows; COUNT(col) skips NULLs in that column.
中文
GROUP BY 为每个组(group)生成一个汇总行。HAVING 用来筛选这些组——它像 WHERE,但在分组之后才运行。
CREATE TABLE student (id INTEGER, name TEXT, form TEXT, score INTEGER);
INSERT INTO student VALUES (1,'Mei','11A',88),(2,'Sam','11B',71),(3,'Ana','11A',95);
SELECT form, COUNT(*) AS n, ROUND(AVG(score), 2) AS avg_score
FROM student
GROUP BY form
HAVING COUNT(*) > 1;
A primary key 主键 uniquely names each row in a table. A foreign key 外键 in one table points to the primary key of another — that builds a relationship 关系 between them.
CREATE TABLE class (id INTEGER, name TEXT);
CREATE TABLE student (id INTEGER, name TEXT, class_id INTEGER);
INSERT INTO class VALUES (1, 'Maths'), (2, 'Art');
INSERT INTO student VALUES (1, 'Mei', 1), (2, 'Sam', 2);
SELECT * FROM student;
5.2
INNER JOIN · INNER JOIN内连接
English
A join 连接 combines rows from two tables. INNER JOIN ... ON ... keeps rows where the keys match. A short alias 别名 (s, c) keeps the query readable.
中文
连接(join)把两张表的行组合起来。INNER JOIN ... ON ... 只保留键匹配的行。用短别名(alias)(s、c)让查询更易读。
CREATE TABLE class (id INTEGER, name TEXT);
CREATE TABLE student (id INTEGER, name TEXT, class_id INTEGER);
INSERT INTO class VALUES (1, 'Maths'), (2, 'Art');
INSERT INTO student VALUES (1, 'Mei', 1), (2, 'Sam', 2);
SELECT s.name, c.name AS class
FROM student s INNER JOIN class c ON s.class_id = c.id;
INNER JOIN 用外键匹配主键,把匹配上的行组合起来
5.3
连接与分组
English
Join first, then GROUP BY to summarise across the joined rows.
中文
先连接,再用 GROUP BY 对连接后的行做汇总。
CREATE TABLE class (id INTEGER, name TEXT);
CREATE TABLE student (id INTEGER, name TEXT, class_id INTEGER);
INSERT INTO class VALUES (1, 'Maths'), (2, 'Art');
INSERT INTO student VALUES (1, 'Mei', 1), (2, 'Sam', 2), (3, 'Ana', 1);
SELECT c.name AS class, COUNT(*) AS n
FROM student s INNER JOIN class c ON s.class_id = c.id
GROUP BY c.name;
5.4
LEFT JOIN 左连接
English
An INNER JOIN keeps only matched rows. A LEFT JOIN 左连接 keeps every row of the left (first) table; where there is no match, the right table's columns come back as NULL.
Sam has no class, but the row still appears — with class as NULL.
To find only the unmatched rows, add WHERE c.id IS NULL.
Common mistakes
A join with no ON condition pairs every row with every row (a cross join).
Match the foreign key to the primary key: ON orders.customer_id = customers.id.
An INNER JOIN drops rows that have no match on the other side; use a LEFT JOIN to keep them.
CREATE TABLE class (id INTEGER, name TEXT);
CREATE TABLE student (id INTEGER, name TEXT, class_id INTEGER);
INSERT INTO class VALUES (1, 'Maths'), (2, 'Art');
INSERT INTO student VALUES (1, 'Mei', 1), (2, 'Sam', NULL);
SELECT s.name, c.name AS class
FROM student s LEFT JOIN class c ON s.class_id = c.id;
INSERT INTO ... VALUES ... adds new rows 行. Name the columns, then give the values in the same order. (Each block below ends with a SELECT so you can see the result.)
INSERT INTO t VALUES (...), (...); adds several rows in one statement.
中文
INSERT INTO ... VALUES ... 添加新的行(row)。先写出列名,再按相同顺序给出值。(下面每个代码块都以 SELECT 结尾,这样你能看到结果。)
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student (id, name, score) VALUES (1, 'Mei', 88);
INSERT INTO student VALUES (2, 'Sam', 71);
SELECT * FROM student;
INSERT INTO t VALUES (...), (...); 一条语句插入多行。
INSERT adds a new row to a table
6.2
UPDATE · UPDATE 更新行
English
UPDATE ... SET ... WHERE ... changes existing rows. Always add WHERE, or every row changes.
中文
UPDATE ... SET ... WHERE ... 改变已有的行。一定要加 WHERE,否则每一行都会被改。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71);
UPDATE student SET score = 75 WHERE name = 'Sam';
SELECT * FROM student;
6.3
DELETE · DELETE 删除行
English
DELETE FROM ... WHERE ... removes rows. Without WHERE it empties the whole table 表.
Common mistakes
UPDATE and DELETEwithout a WHERE change every row — always add the WHERE.
In INSERT, the values must line up with the column list in order and type.
Test a risky DELETE first as a SELECT with the same WHERE.
中文
DELETE FROM ... WHERE ... 删除行。没有 WHERE 时,它会清空整张表(table)。
CREATE TABLE student (id INTEGER, name TEXT, score INTEGER);
INSERT INTO student VALUES (1, 'Mei', 88), (2, 'Sam', 71);
DELETE FROM student WHERE score < 80;
SELECT * FROM student;
CREATE TABLE defines a table's schema 表结构: the column names and their data types 数据类型. The main SQLite types are INTEGER, TEXT, and REAL (a decimal number).
CREATE TABLE student (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
score INTEGER DEFAULT 0
);
INSERT INTO student (id, name) VALUES (1, 'Mei');
SELECT * FROM student;
用 REFERENCES 声明外键——它记录这一列指向另一张表的主键:
CREATE TABLE class (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE student (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
class_id INTEGER REFERENCES class(id)
);
INSERT INTO class VALUES (1, 'Maths');
INSERT INTO student VALUES (1, 'Mei', 1);
SELECT s.name, c.name AS class
FROM student s INNER JOIN class c ON s.class_id = c.id;
Tables connect through relationships 关系. One-to-many 一对多 is the most common: one class has many students. Many-to-many 多对多 needs a join table 连接表 in the middle. An entity-relationship diagram 实体关系图 (ER diagram) draws each entity 实体 as a box and each relationship as a line.
Relationship
Example
one-to-one
a person and their passport
one-to-many
a class and its students
many-to-many
students and clubs
The join table holds one row per link. Here Mei is in two clubs, and Chess has two members:
CREATE TABLE student (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE club (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE membership (student_id INTEGER, club_id INTEGER);
INSERT INTO student VALUES (1, 'Mei'), (2, 'Sam');
INSERT INTO club VALUES (1, 'Chess'), (2, 'Art');
INSERT INTO membership VALUES (1, 1), (1, 2), (2, 1);
SELECT s.name, c.name AS club
FROM membership m
INNER JOIN student s ON m.student_id = s.id
INNER JOIN club c ON m.club_id = c.id;
8.2
范式化
English
Normalisation 范式化 organises tables to avoid redundancy 冗余 (the same data repeated) and the update mistakes it causes. The first three normal forms 范式:
1NF: every cell holds one atomic 原子 value — no lists inside a cell.
2NF: no column depends on only part of a composite key 复合主键.
3NF: no column depends on another non-key column.
Unnormalised (bad)
Normalised (better)
student(name, club1, club2)
student(name) + membership(student, club)
Common mistakes
Split repeating groups into their own table (normalisation) instead of many similar columns.
Each table should describe ONE kind of thing.
Link tables with a foreign key that points to another table's primary key.