如果你想有一个 users 表并且每个用户都可以有宠物。你首先要做一个宠物桌。
create table pets (
id integer primary key,
name text not null,
hunger int not null default 0
);
那么这取决于宠物是只有一个主人(称为一对多关系)还是有多个主人(称为多对多关系)。
如果宠物有一个主人,则将带有用户 ID 的列添加到 pets 表中。这是foreign key。
create table pets (
id integer primary key,
-- When a user is deleted, their pet's user_id will be set to null.
user_id integer references users(id) on delete set null,
name text not null,
hunger int not null default 0
);
获取一个用户的所有宠物...
select pets.*
from pets
where user_id = ?
为了获取宠物主人的姓名,我们使用pets.user_id 和users.id 将每行宠物与其主人的行进行匹配。
select users.name
from users
join pets on pets.user_id = users.id
where pets.id = ?
如果每个宠物可以有多个主人,多对多的关系,我们不会将 user_id 放入宠物中。相反,我们需要一个额外的表:连接表。
create table pet_owners (
-- When a user or pet is deleted, delete the rows relating them.
pet_id integer not null references pets(id) on delete cascade,
user_id integer not null references users(id) on delete cascade
);
我们通过插入此表来声明用户拥有宠物。
-- Pet 5 is owned by users 23 and 42.
insert into pet_owners (pet_id, user_id) values (5, 23), (5, 42);
要查找用户的宠物及其姓名,我们查询 pet_owners 并与宠物连接以获取姓名。
select pets.*
from pet_owners
join pets on pet_owners.pet_id = pets.id
where user_id = ?
这可能看起来很奇怪和尴尬,但它就是 SQL 数据库如此强大和快速的原因。这样做是为了避免对数据库中的内容进行任何解析或解释。这允许数据库使用indexes 有效地查询数据,而不必筛选所有数据。这使得即使是非常大的数据库也很高效。
查询select pets.* from pets where user_id = ?时,由于外键被索引,SQLite不会搜索整个pets表。它使用 user_id 上的索引直接跳转到匹配的记录。这意味着数据库将对 10 或 1000 万只宠物执行相同的操作。