结构化查询语言(Structured Query Language)
超过电子表格
rDBMS 提供了多种将数据存储到其存储系统中的方式:从 CSV 文件、Excel 文件、特定产品的二进制文件,通过多个 API 或专用网关连接到其他数据库或数据库系统,以及其他一些技术。因此,存在广泛的——非标准化的——将数据引入我们系统的可能性。由于我们讨论的是 SQL,我们使用标准化的 INSERT
命令来完成这项工作。它在所有系统上都是可用的。
我们仅使用少量数据,因为我们希望保持简单。有时需要大量行来进行性能测试。为此,我们在本页末尾展示了一个特殊的 INSERT
命令,它可以指数级地膨胀您的表格。
person
-- 在进行大量测试后,我们可能希望将数据重置为原始版本。
-- 为此,使用 DELETE 命令。但请注意外键:您可能被迫最后删除
-- person 表中的记录 —— 使用 DELETE 时,删除表的顺序与 INSERT 时相反。
-- 请小心,不要将 DELETE 与 DROP 混淆 !!
--
-- DELETE FROM person_hobby;
-- DELETE FROM hobby;
-- DELETE FROM contact;
-- DELETE FROM person;
-- COMMIT;
INSERT INTO person VALUES (1, 'Larry', 'Goldstein', DATE'1970-11-20', 'Dallas', '078-05-1120', 95);
INSERT INTO person VALUES (2, 'Tom', 'Burton', DATE'1977-01-22', 'Birmingham', '078-05-1121', 75);
INSERT INTO person VALUES (3, 'Lisa', 'Hamilton', DATE'1975-12-23', 'Richland', '078-05-1122', 56);
INSERT INTO person VALUES (4, 'Kim', 'Goldstein', DATE'2011-06-01', 'Shanghai', '078-05-1123', 11);
INSERT INTO person VALUES (5, 'James', 'de Winter', DATE'1975-12-23', 'San Francisco', '078-05-1124', 75);
INSERT INTO person VALUES (6, 'Elias', 'Baker', DATE'1939-10-03', 'San Francisco', '078-05-1125', 55);
INSERT INTO person VALUES (7, 'Yorgos', 'Stefanos', DATE'1975-12-23', 'Athens', '078-05-1126', 64);
INSERT INTO person VALUES (8, 'John', 'de Winter', DATE'1977-01-22', 'San Francisco', '078-05-1127', 77);
INSERT INTO person VALUES (9, 'Richie', 'Rich', DATE'1975-12-23', 'Richland', '078-05-1128', 90);
INSERT INTO person VALUES (10, 'Victor', 'de Winter', DATE'1979-02-28', 'San Francisco', '078-05-1129', 78);
COMMIT;
请注意,DATE
的格式可能取决于您的本地环境。此外,SQLite 使用不同的语法将字符串隐式转换为 DATE
。
-- SQLite 语法
INSERT INTO person VALUES (1, 'Larry', 'Goldstein', DATE('1970-11-20'), 'Dallas', '078-05-1120', 95);
...
contact
-- DELETE FROM contact;
-- COMMIT;
INSERT INTO contact VALUES (1, 1, 'fixed line', '555-0100');
INSERT INTO contact VALUES (2, 1, 'email', 'larry.goldstein@acme.xx');
INSERT INTO contact VALUES (3, 1, 'email', 'lg@my_company.xx');
INSERT INTO contact VALUES (4, 1, 'icq', '12111');
INSERT INTO contact VALUES (5, 4, 'fixed line', '5550101');
INSERT INTO contact VALUES (6, 4, 'mobile', '10123444444');
INSERT INTO contact VALUES (7, 5, 'email', 'james.dewinter@acme.xx');
INSERT INTO contact VALUES (8, 7, 'fixed line', '+30000000000000');
INSERT INTO contact VALUES (9, 7, 'mobile', '+30695100000000');
COMMIT;
hobby
-- DELETE FROM hobby;
-- COMMIT;
INSERT INTO hobby VALUES (1, 'Painting',
'Applying paint, pigment, color or other medium to a surface.');
INSERT INTO hobby VALUES (2, 'Fishing',
'Catching fishes.');
INSERT INTO hobby VALUES (3, 'Underwater Diving',
'Going underwater with or without breathing apparatus (scuba diving / breath-holding).');
INSERT INTO hobby VALUES (4, 'Chess',
'Two players have 16 figures each. They move them on an eight-by-eight grid according to special rules.');
INSERT INTO hobby VALUES (5, 'Literature', 'Reading books.');
INSERT INTO hobby VALUES (6, 'Yoga',
'A physical, mental, and spiritual practices which originated in ancient India.');
INSERT INTO hobby VALUES (7, 'Stamp collecting',
'Collecting of post stamps and related objects.');
INSERT INTO hobby VALUES (8, 'Astronomy',
'Observing astronomical objects such as moons, planets, stars, nebulae, and galaxies.');
INSERT INTO hobby VALUES (9, 'Microscopy',
'Observing very small objects using a microscope.');
COMMIT;
person_hobby
-- DELETE FROM person_hobby;
-- COMMIT;
INSERT INTO person_hobby VALUES (1, 1, 1);
INSERT INTO person_hobby VALUES (2, 1, 4);
INSERT INTO person_hobby VALUES (3, 1, 5);
INSERT INTO person_hobby VALUES (4, 5, 2);
INSERT INTO person_hobby VALUES (5, 5, 3);
INSERT INTO person_hobby VALUES (6, 7, 8);
INSERT INTO person_hobby VALUES (7, 4, 4);
INSERT INTO person_hobby VALUES (8, 9, 8);
INSERT INTO person_hobby VALUES (9, 9, 9);
COMMIT;
每一行 person_hobby
表包含一个来自 person
表的 id
和一个来自 hobby
表的 id
。这是将人物和爱好信息关联起来的技术。
结构的可视化
执行上述命令后,您的数据库应包含四个表(没有任何数据)。这些表及其相互关系可以在所谓的实体关系图(Entity Relationship Diagram)中可视化。左侧是 person
和 contact
之间的 1:n 关系,右侧是 person
和 hobby
之间的 n:m 关系,以及其中间的 person_hobby
表。
您可以根据需要复制/粘贴这些示例,以帮助您学习和实践SQL。
超大数据量
为了进行现实的性能测试,我们需要大量的数据。我们示例数据库中仅有的几行数据无法满足这一标准。我们如何生成测试数据并将其存储到表中?有多种可能性:在过程中的 FOR
循环,(伪)递归调用,以系统特定的方式导入外部数据,以及其他一些方法。
由于我们正在处理 SQL,我们介绍一个跨所有 rDBMS 可移植的 INSERT
命令。尽管它的语法简单,但功能非常强大。每次执行,它将使行数翻倍。假设表中有 1 行。第一次执行后,表中将有第二行。乍一看,这听起来很无聊。但经过 10 次执行后,行数超过一千,20 次执行后超过一百万,我们怀疑只有极少数安装能够执行超过 30 次。
INSERT INTO person (id, firstname, lastname, weight)
SELECT id + (SELECT MAX(id) FROM person), firstname, lastname, weight
FROM person;
COMMIT;
该命令是 INSERT
与(子)SELECT
的组合。SELECT
检索表中的所有行,因为没有 WHERE
子句。这就是行数翻倍的原因。强制性的列 firstname
和 lastname
保持不变。我们忽略了可选列。只有主键 id
被计算。新值是旧值加上执行命令时的最高可用 id
。
其他备注:
-
MAX(id)
仅在每次执行时确定一次! 这说明了 rDBMS 的一个基本方面:在概念层面上,数据库在执行命令前具有特定的状态,在执行命令后具有新的状态。命令是将数据库从一个状态移动到另一个状态的原子操作——它们要么完全执行,要么完全不执行!SELECT
和内部SELECT
(使用MAX(id)
)都在初始状态上操作。它们永远不会看到INSERT
的结果或中间结果。否则,INSERT
将永远不会结束。 -
如果我们希望观察增长过程,可以向表中添加一列,以在每次迭代时存储
MAX(id)
。 -
如果 DBMS 支持自动递增列,可以省略新
id
的计算。 -
对于性能测试,可能有助于在一个或多个列中存储一些随机数据。
您可以根据需要复制/粘贴这些示例,以帮助您学习和实践SQL。