结构化查询语言/示例数据库结构
首先,数据库是数据的集合。这些数据按表的形式组织,如示例中的person表所示。此外,DBMS 中还有许多其他类型的对象:视图、函数、过程、索引、权限等等。最初我们关注表,并展示其中四个表,它们作为我们维基教科书的基础。其他类型的对象将在稍后介绍。
我们尽量保持所有内容尽可能简单。然而,这四个表的极简集合演示了 1:n 关系以及 n:m 关系。
person表保存虚构人物的信息;请参见:创建简单表.
-- comment lines start with two consecutive minus signs '--'
CREATE TABLE person (
-- define columns (name / type / default value / nullable)
id DECIMAL NOT NULL,
firstname VARCHAR(50) NOT NULL,
lastname VARCHAR(50) NOT NULL,
date_of_birth DATE,
place_of_birth VARCHAR(50),
ssn CHAR(11),
weight DECIMAL DEFAULT 0 NOT NULL,
-- select one of the defined columns as the Primary Key and
-- guess a meaningfull name for the Primary Key constraint: 'person_pk' may be a good choice
CONSTRAINT person_pk PRIMARY KEY (id)
);
contact表保存一些人物的联系信息。人们可能会考虑将这些联系信息存储在person表的附加列中:一列用于电子邮件,一列用于 ICQ,等等。我们出于一些重要原因而拒绝了这种做法。
- 缺失值:许多人并没有大多数这些联系值,或者我们不知道这些值。因此,该表将看起来像一个稀疏矩阵。
- 多重性:其他人拥有多个电子邮件地址或多个电话号码。我们是否要定义许多列 email_1、email_2,...?上限是多少?标准 SQL 没有提供类似于列“值数组”的东西(一些实现提供了)。
- 未来扩展:总有一天,会有一些今天未知的联系类型。那么我们必须修改该表。
当联系数据进入它自己的表时,我们可以以一种简单的方式处理所有这些情况。唯一特殊的是将人员与他们的联系数据联系起来。这项任务将由contact表的person_id列来管理。它保存与分配人员的主键相同的值。
一般来说,我们有一个信息单元(person),它可能拥有多个相同类型(contact)的信息单元。我们将这种组合关系称为关系 - 在这种情况下是1:m 关系(也称为一对多关系)。每当遇到这种情况,我们都会将可能出现多次的值存储在一个单独的表中,以及第一个表的 id。
CREATE TABLE contact (
-- define columns (name / type / default value / nullable)
id DECIMAL NOT NULL,
person_id DECIMAL NOT NULL,
-- use a default value, if contact_type is omitted
contact_type VARCHAR(25) DEFAULT 'email' NOT NULL,
contact_value VARCHAR(50) NOT NULL,
-- select one of the defined columns as the Primary Key
CONSTRAINT contact_pk PRIMARY KEY (id),
-- define Foreign Key relation between column person_id and column id of table person
CONSTRAINT contact_fk FOREIGN KEY (person_id) REFERENCES person(id),
-- more constraint(s)
CONSTRAINT contact_check CHECK (contact_type IN ('fixed line', 'mobile', 'email', 'icq', 'skype'))
);
人们通常从事一项或多项爱好。关于多重性,我们遇到了与contact表相同的问题。因此,我们需要为爱好创建一个单独的表。
CREATE TABLE hobby (
-- define columns (name / type / default value / nullable)
id DECIMAL NOT NULL,
hobbyname VARCHAR(100) NOT NULL,
remark VARCHAR(1000),
-- select one of the defined columns as the Primary Key
CONSTRAINT hobby_pk PRIMARY KEY (id),
-- forbid duplicate recording of a hobby
CONSTRAINT hobby_unique UNIQUE (hobbyname)
);
你可能已经注意到,表中没有与之对应的列。为什么?对于爱好,我们还有一个额外的难题:不仅仅是一个人从事多个爱好,同时,多个人从事相同的爱好。
我们将这种组合关系称为n:m 关系。可以通过在两个原始表之间创建一个第三张表来设计它。第三张表保存第一个表和第二个表的 id。因此,人们可以决定哪个人从事哪项爱好。在我们的示例中,这个“中间表”是person_hobby,将在下面定义。
CREATE TABLE person_hobby (
-- define columns (name / type / default value / nullable)
id DECIMAL NOT NULL,
person_id DECIMAL NOT NULL,
hobby_id DECIMAL NOT NULL,
-- Also this table has its own Primary Key!
CONSTRAINT person_hobby_pk PRIMARY KEY (id),
-- define Foreign Key relation between column person_id and column id of table person
CONSTRAINT person_hobby_fk_1 FOREIGN KEY (person_id) REFERENCES person(id),
-- define Foreign Key relation between column hobby_id and column id of table hobby
CONSTRAINT person_hobby_fk_2 FOREIGN KEY (hobby_id) REFERENCES hobby(id)
);
该表的每一行都保存person表中的一个 id 和hobby表中的一个 id。这是将人员和爱好信息连接在一起的技术。
执行上述命令后,您的数据库应该包含四个表(没有任何数据)。表及其彼此之间的关系可以在所谓的实体关系图中可视化。左侧是person和contact之间的 1:n 关系,右侧是person和hobby之间的 n:m 关系,以及它的“中间表”person_hobby。