跳转到内容

结构化查询语言/INSERT 2

来自维基教科书,自由的教科书



提示:小心,并停用 AUTOCOMMIT.

INSERT 命令的基本语法和语义在 INSERT 页面中描述。该页面提供了一些将固定值插入表的单行的示例。本页描述了如何使用子查询来使命令更动态。

运行时评估值

[编辑 | 编辑源代码]

首先,可以通过读取系统时间或其他(准)常量来相对严格地评估要插入的值。

-- Use the key word CURRENT_DATE to determine the actual day.
INSERT INTO person ( id,  firstname,        lastname,    date_of_birth,     place_of_birth, ssn,           weight)
VALUES             (101,  'Larry, no. 101', 'Goldstein', CURRENT_DATE,      'Dallas',       '078-05-1120', 95);
COMMIT;


接下来,可以通过 标量值子查询 来评估要插入的值。这意味着,基于同一表或另一表的行,可以在运行时计算单个值。

-- Count the number of rows to determine the next ID. Caution: This handling of IDs is absolutely NOT recommended for real applications!
INSERT INTO person ( id,   firstname,        lastname,    date_of_birth,     place_of_birth, ssn,           weight)
VALUES             ((SELECT COUNT(*) + 1000 FROM person),  -- This scalar-value subquery computes a single value, the new ID.
-- VALUES          ((Select * FROM (SELECT COUNT(*) + 1000 FROM person) tmp), -- MySQL insists in using an intermediate table
                           'Larry, no. ?',   'Goldstein', CURRENT_DATE,      'Dallas',       '078-05-1120', 95);
COMMIT;


运行时评估行

[编辑 | 编辑源代码]

与之前从标量值子查询获取单个标量值的示例类似,可以使用 表子查询 获取多行,并将它们插入到一个 INSERT 命令中指定的表中。此版本能够使用单个语句插入数千行。除了其动态特性外,它还可以节省除一次之外的应用程序和 DBMS 之间的往返次数,因此比许多基于单行的 INSERT 快得多。

-- The statement doubles the number of rows within the table. It omits in the table subquery the WHERE clause and therefore
-- it reads all existing rows. Caution: This handling of IDs is absolutely NOT recommended for real applications!
INSERT INTO person (id,          firstname, lastname, date_of_birth, place_of_birth, ssn, weight)
  SELECT            id + 1100,   firstname, lastname, date_of_birth, place_of_birth, ssn, weight
  FROM   person;
COMMIT;

语法发生变化,以便使用完整的子查询替换关键字 'VALUES'及其值列表(通常称为'subselect'),该列表以关键字 'SELECT' 开头。当然,所选列的数量和类型必须与关键字 'INSERT INTO' 后面的指定列列表中的列的数量和类型相对应。在子查询中,SELECT 语句的全部功能都可以使用:JOIN、WHERE、GROUP BY、ORDER BY,尤其是其他子查询以递归方式使用。存在各种各样的用例:创建具有增加版本号的行、具有百分比增加工资的行、具有实际时间戳的行、来自同一表或另一表的行的固定值等等。

-- The next two statements compute different weights depending on the old weight
INSERT INTO person (id,          firstname, lastname, date_of_birth, place_of_birth, ssn, weight)
  -- the subquery starts here
  SELECT            id + 1200,   firstname, lastname, date_of_birth, place_of_birth, ssn,
                    CASE WHEN weight < 40 THEN weight + 10
                         ELSE                  weight +  5
                         END
  FROM   person
  WHERE  id <= 10;                          -- only the original 10 rows from the example database
COMMIT;

-- The same semantic with a more complex syntax (to demonstrate the power of subselect)
INSERT INTO person (id,          firstname, lastname, date_of_birth, place_of_birth, ssn, weight)
  -- the first subquery starts here
  SELECT            id + 1300,   firstname, lastname, date_of_birth, place_of_birth, ssn,
                     -- here starts a subquery of the first subquery. The CASE construct evaluates different
                     -- weights depending on the old weight.
                    (SELECT CASE WHEN weight < 40 THEN weight + 10
                                 ELSE                  weight +  5
                                 END
                     FROM   person ssq      -- alias for the table name in sub-subquery
                     WHERE  sq.id = ssq.id  -- link the rows together
                    )
  FROM   person sq                          -- alias for the table name in subquery
  WHERE  id <= 10;                          -- only the original 10 rows from the example database
COMMIT;

结构化查询语言/示例数据库数据#Grow_up 中所示的技术,它将现有数据(例如,用于测试目的)倍增,就是基于这样的表子查询。

清理您的数据库

[编辑 | 编辑源代码]
DELETE FROM person WHERE id > 100;
COMMIT;

插入一个新的联系人,id 为 1301,姓氏为 'Mr. Mean',姓氏为最小的姓氏(按字符编码,使用 min() 函数)。其体重为所有联系人的平均体重(使用 avg() 函数)。

点击查看解决方案
-- Two columns are computed during runtime
INSERT INTO person (id,   firstname,  lastname, weight)
VALUES             (1301,
                    'Mr. Mean',
                    (SELECT MIN(lastname) FROM person),
                    (SELECT AVG(weight)   FROM person)
-- the MySQL version with its intermediate tables
--                  (SELECT * FROM (SELECT MIN(lastname) FROM person) tmp1),
--                  (SELECT * FROM (SELECT AVG(weight)   FROM person) tmp2)
                   );
COMMIT;
-- Check your result
SELECT * FROM person WHERE id = 1301;

为每个家庭(=姓氏)插入一个额外的联系人,姓氏为 'An extraordinary family member',姓氏为家庭姓氏。仅合并原始示例数据库中 id<=10 的行。

点击查看解决方案
-- Two columns are computed during runtime. The number of involved rows is delimited by the WHERE clause.
INSERT INTO person (id,   firstname,  lastname)
  -- here starts the subquery
  SELECT MAX(id) + 1310,  -- in this case the max() function works per group
         'An extraordinary family member',
         lastname
  FROM   person
  WHERE  id <= 10
  GROUP BY lastname;
COMMIT;
-- Check your result
SELECT * FROM person WHERE id > 1310;

清理您的数据库。

点击查看解决方案
DELETE FROM person WHERE id > 1300;
COMMIT;


华夏公益教科书