将表从一个 MariaDB 数据库克隆到另一个数据库,包括默认值、索引和触发器?

4 mysql sql database mariadb

我想将一个表(包括其索引和触发器)从一个数据库复制到另一个数据库。这并不像我希望的那么简单。这是一个用于演示的最小工作示例 (MWE)。首先,我的 MariaDB 版本:

$ mysql --version
mysql  Ver 15.1 Distrib 10.0.29-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Run Code Online (Sandbox Code Playgroud)

接下来是第一个表:

CREATE DATABASE db1;
USE db1;
CREATE TABLE tb1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    word VARCHAR(50) NOT NULL);
INSERT INTO tb1 (word) VALUES ('foo');
DELETE FROM tb1 WHERE word='foo';
DELIMITER $$
CREATE TRIGGER before_word_insert BEFORE INSERT ON tb1 FOR EACH ROW
    BEGIN
        SET NEW.word=TRIM(NEW.word);
        IF NOT (NEW.word REGEXP '^[[:alpha:]]+$') THEN
            SIGNAL SQLSTATE '12345' SET MESSAGE_TEXT = 'Invalid word';
        END IF;
    END$$
DELIMITER ;
INSERT INTO tb1 (word) VALUES ('foo');
DESCRIBE tb1;
SHOW TRIGGERS;
SHOW INDEX FROM tb1;
Run Code Online (Sandbox Code Playgroud)

最后三行给出:

+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| word  | varchar(50) | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

+--------------------+--------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| Trigger            | Event  | Table | Statement                                                                                                                                                | Timing | Created | sql_mode | Definer        | character_set_client | collation_connection | Database Collation |
+--------------------+--------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| before_word_insert | INSERT | tb1   | BEGIN SET NEW.word=TRIM(NEW.word); IF NOT (NEW.word REGEXP '^[[:alpha:]]+$') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Invalid word'; END IF; END | BEFORE | NULL    |          | root@localhost | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
+--------------------+--------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
1 row in set (0.04 sec)

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tb1   |          0 | PRIMARY  |            1 | id          | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。现在,复制tb1到另一个数据库(在同一台服务器上):

CREATE DATABASE db2;
USE db2;
CREATE TABLE db2.tb1 AS SELECT * FROM db1.tb1;
DESCRIBE tb1;
SHOW TRIGGERS;
SHOW INDEX FROM tb1;
Run Code Online (Sandbox Code Playgroud)

我曾希望这最后三行会给出与它们相同的输出db1,但它们没有:

+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | 0       |       |
| word  | varchar(50) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Empty set (0.00 sec)

Empty set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

换句话说,CREATE TABLE db2.tb1 AS SELECT * FROM db1.tb1;

  • 复制表格内容;
  • 复制列类型;
  • 没有复制“Key”属性;
  • 没有复制“默认”属性;
  • 没有复制“额外”属性;
  • 没有复制触发器;和
  • 没有复制索引。

我的问题:什么是简洁的等效项CREATE TABLE db2.tb1 AS SELECT * FROM db1.tb1;可以复制所有丢失的项目?

Psi*_*Psi 6

CREATE TABLE newTable LIKE oldTable
Run Code Online (Sandbox Code Playgroud)

应该包括索引和设置,但不包括数据和触发器。

之后,您需要复制数据:

INSERT INTO newTable SELECT * FROM oldTable
Run Code Online (Sandbox Code Playgroud)

触发器不是表的直接一部分,而是脚本管理的一部分。

您可以在 中找到触发器information_schema.triggers。在那里您可以查询为您的表设置的每个触发器。但我强烈建议不要手动处理该表

相反,您可以阅读那里的定义并使用SHOW CREATE TRIGGERand创建一个新触发器CREATE TRIGGER。这涉及动态 sql 或能够操作 sql 的客户端(这应该适用于每个客户端)。

如果有一个客户端连接到源数据库和目标数据库,您可以执行以下操作:

SELECT `TRIGGER_NAME` FROM information_schema.triggers WHERE `TRIGGER_SCHEMA` = database() AND `EVENT_OBJECT_TABLE` = oldTableName
Run Code Online (Sandbox Code Playgroud)

正如您在评论中所述,您也可以使用

SHOW TRIGGERS WHERE `Table` = "oldTable"
Run Code Online (Sandbox Code Playgroud)

而不是读取触发器表。作为旁注,这些反引号Table很重要,因为它Table是一个保留字,在这里以类似于列名的方式使用。

使用触发器名称,对于每个触发器,您可以使用

SHOW CREATE TRIGGER triggerNameFromQueryAbove
Run Code Online (Sandbox Code Playgroud)

这为您提供了可用于在新数据库中创建触发器的 create 语句。但请注意:可能包含数据库名称和定义者,新数据库中可能不存在这些信息,因此您必须手动删除该信息。

有关“触发器”表的更多信息,请阅读 mysql 手册(也应适用于 mariadb):https ://dev.mysql.com/doc/refman/5.7/en/triggers-table.html