跳至内容

结构化查询语言/示例数据库结构

来自维基教科书,开放的书籍,开放的世界


首先,数据库是数据的集合。这些数据按表的形式组织,如示例中的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,将在下面定义。

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。这是将人员和爱好信息连接在一起的技术。

结构的可视化

[编辑 | 编辑源代码]

执行上述命令后,您的数据库应该包含四个表(没有任何数据)。表及其彼此之间的关系可以在所谓的实体关系图中可视化。左侧是personcontact之间的 1:n 关系,右侧是personhobby之间的 n:m 关系,以及它的“中间表”person_hobby

我们示例数据库的视觉表示


华夏公益教科书