跳到正文
IntoSQL 首页

将 MariaDB 转换为 SQLite

拖入由 mariadb-dump、mysqldump、phpMyAdmin 或 Adminer 生成的转储(.sql 或 .sql.gz),即可下载包含相同表、键、索引和数据的 SQLite 脚本。SQLite 无法原样存储的每个值,以及它不支持的每个对象,都会在报告中列出。

你的文件
sqlshop_2024_mariadb.sql示例文件,6.6 kB
你的数据库

已转换 18 行,8 处修正,无拒绝

显示

shop_2024_mariadb.sql 中的表MariaDB 11.8.9-MariaDB-ubu2404 转储 · 由 mariadb-dump 写出 · utf8mb4

  • customers8 行3
    8 列
    idINTEGER not null
    nameVARCHAR(100) not null
    emailVARCHAR(150) not null
    countryVARCHAR(2) not null
    is_activeINTEGER not null
    signed_upDATE
    created_atTIMESTAMP not null
    last_ipTEXT
  • orders10 行5
    12 列
    idINTEGER not null
    customer_idINTEGER not null
    statusTEXT not null
    totalDECIMAL(10,2) not null
    itemsINTEGER not null
    ordered_atDATETIME not null
    shipped_atDATETIME
    noteVARCHAR(255)
    order_refTEXT not null
    invoiceINTEGER not null
    detailsTEXT
    updated_atTIMESTAMP not null
-- Written by IntoSQL from a MySQL dump. Load it with: sqlite3 -bail <database> < <file>
PRAGMA foreign_keys = OFF;
PRAGMA synchronous = OFF;
BEGIN;

CREATE TABLE customers ( -- People who bought at least once
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL,
    country VARCHAR(2) DEFAULT 'US' NOT NULL,
    is_active INTEGER DEFAULT 1 NOT NULL,
    signed_up DATE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    last_ip TEXT,
    CONSTRAINT customers_id_check CHECK (id >= 0)
);

CREATE TABLE orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    customer_id INTEGER NOT NULL,
    status TEXT DEFAULT 'pending' NOT NULL,
    total DECIMAL(10,2) NOT NULL,
    items INTEGER DEFAULT 1 NOT NULL,
    ordered_at DATETIME NOT NULL,
    shipped_at DATETIME,
    note VARCHAR(255),
    order_ref TEXT NOT NULL,
    invoice INTEGER NOT NULL,
    details TEXT,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT orders_id_check CHECK (id >= 0),
    CONSTRAINT orders_customer_id_check CHECK (customer_id >= 0),
    CONSTRAINT orders_status_check CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled', '')),
    CONSTRAINT orders_items_check CHECK (items >= 0),
    CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers (id)
);

INSERT INTO customers (id, name, email, country, is_active, signed_up, created_at, last_ip) VALUES
(1,'Ana Martínez','ana@example.com','MX',1,'2023-01-15','2023-01-15 10:24:00','::ffff:203.0.113.7'),
(2,'Zoë Müller','zoe@example.de','DE',1,'2023-02-03','2023-02-03 08:11:42','2001:db8::1'),
(3,'José Peña','jose@example.es','ES',0,'2023-03-21','2023-03-21 19:05:17',NULL),
(4,'李雷','lilei@example.cn','CN',1,'2023-05-09','2023-05-09 02:40:00','::ffff:198.51.100.23'),
(5,'Noah O''Brien','noah@example.ie','IE',1,NULL,'2023-06-30 14:00:00',NULL),
(6,'Amélie Laurent','amelie@example.fr','FR',1,'2024-01-02','2024-01-02 09:30:00','2001:db8:85a3::8a2e:370:7334'),
(7,'Ravi Patel','ravi@example.in','IN',0,'2024-02-29','2024-02-29 23:59:59','::ffff:192.0.2.200'),
(8,'Sofia Rossi 🌻','sofia@example.it','IT',1,'2024-04-12','2024-04-12 12:12:12',NULL);
INSERT INTO orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, order_ref, invoice, details, updated_at) VALUES
(1,1,'shipped',129.90,3,'2024-03-01 10:00:00','2024-03-02 16:30:00',NULL,'0b7a4c2e-3f1d-4e8a-9c55-1a2b3c4d5e6f',1000,'{"gift": false}','2024-03-02 16:30:00'),
(2,2,'paid',54.00,1,'2024-03-02 11:15:00',NULL,'Gift wrap 🎁','1c8b5d3f-4a2e-4f9b-8d66-2b3c4d5e6f70',1001,'{"gift": true, "wrap": "red"}','2024-03-02 11:20:00'),
(3,1,'cancelled',12.50,1,'2024-03-03 09:45:00',NULL,'Customer changed their mind','2d9c6e4a-5b3f-4a0c-9e77-3c4d5e6f7081',1002,NULL,'2024-03-03 10:00:00'),
(4,4,'shipped',980.00,12,'2024-03-05 02:10:00','2024-03-07 08:00:00','请小心轻放','3e0d7f5b-6c4a-4b1d-8f88-4d5e6f708192',1003,'{"fragile": true}','2024-03-07 08:00:00'),
(5,5,'pending',45.75,2,'2024-03-08 17:20:00',NULL,'Leave at the door; ring twice','4f1e806c-7d5b-4c2e-9a99-5e6f708192a3',1004,NULL,'2024-03-08 17:20:00'),
(6,6,'shipped',310.40,5,'2024-03-10 13:00:00','2024-03-11 09:00:00','Fragile: "glass"','50f2917d-8e6c-4d3f-8baa-6f708192a3b4',1005,'{"fragile": true}','2024-03-11 09:00:00'),
(7,8,'paid',76.20,2,'2024-03-11 18:45:00',NULL,NULL,'6103a28e-9f7d-4e40-9cbb-708192a3b4c5',1006,NULL,'2024-03-11 18:46:00'),
(8,2,'',19.99,1,'2024-03-12 08:00:00',NULL,'Status lost in an old import','7214b39f-a08e-4f51-8dcc-8192a3b4c5d6',1007,NULL,'2024-03-12 08:00:00'),
(9,3,'shipped',64.00,2,'2024-03-14 15:30:00',NULL,'Shipping date never recorded','8325c4a0-b19f-4062-9edd-92a3b4c5d6e7',1008,'{"parcels": [1, 2]}','2024-03-15 10:00:00'),
(10,7,'paid',1499.00,1,'2024-03-15 21:05:00',NULL,'C:\Users\ravi\invoice.pdf','9436d5b1-c2a0-4173-8fee-a3b4c5d6e7f8',1009,NULL,'2024-03-15 21:05:00');

-- Indexes, triggers and counters, after the rows so each index builds once.
CREATE UNIQUE INDEX customers_uq_email ON customers (email);
CREATE INDEX orders_idx_customer ON orders (customer_id);
CREATE INDEX orders_idx_status_date ON orders (status, ordered_at);
UPDATE sqlite_sequence SET seq = max(seq, 1000) WHERE name = 'customers';
INSERT INTO sqlite_sequence (name, seq) SELECT 'customers', 1000 WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = 'customers');
UPDATE sqlite_sequence SET seq = max(seq, 5000) WHERE name = 'orders';
INSERT INTO sqlite_sequence (name, seq) SELECT 'orders', 5000 WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = 'orders');
CREATE TRIGGER orders_updated_at_on_update AFTER UPDATE ON orders FOR EACH ROW WHEN NEW.updated_at IS OLD.updated_at AND (NEW.id IS NOT OLD.id OR NEW.customer_id IS NOT OLD.customer_id OR NEW.status IS NOT OLD.status OR NEW.total IS NOT OLD.total OR NEW.items IS NOT OLD.items OR NEW.ordered_at IS NOT OLD.ordered_at OR NEW.shipped_at IS NOT OLD.shipped_at OR NEW.note IS NOT OLD.note OR NEW.order_ref IS NOT OLD.order_ref OR NEW.invoice IS NOT OLD.invoice OR NEW.details IS NOT OLD.details)
BEGIN
    UPDATE orders SET updated_at = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
END;
COMMIT;

-- Rows whose foreign key finds no parent, if any: the load doesn't stop for them.
PRAGMA foreign_key_check;

修正

  1. customers 的 "id" 是无符号的,因此变为 INTEGER,并带有不能为负数的检查约束。
  2. customers 的 "signed_up" 现在允许 NULL:它的部分值无法存储,已设为 NULL。
  3. customers 中 "signed_up" 的默认值 0000‑00‑00 不是 SQLite 接受的日期,因此该列没有默认值。
  4. orders 的 "customer_id" 是无符号的,因此变为 INTEGER,并带有不能为负数的检查约束。
  5. orders 的 "id" 是无符号的,因此变为 INTEGER,并带有不能为负数的检查约束。
  6. orders 的 "items" 是无符号的,因此变为 INTEGER,并带有不能为负数的检查约束。
  7. orders 中 "status" 有 1 行包含 MySQL 为无效输入存储的空值;对其值的检查约束允许该值。
  8. orders 的 "updated_at" 在每次更新时变为当前时间;在 SQLite 中由触发器完成。

需要检查

  • 1 个序列未创建;SQLite 没有序列。 如果你的应用需要,请把下一个值保存在表中。
  • customers 的 "signed_up" 中有 1 个值是零日期或不可能的日期,例如 0000‑00‑00,SQLite 无法存储,因此设为 NULL。 如果这些日期有意义,请在转储前于源数据中替换为真实日期。
  • orders 中 "invoice" 的默认值无法为 SQLite 写出(a sequence),因此该列没有默认值。 如果新行需要,请手动添加默认值。
  • orders 的 "shipped_at" 中有 1 个值是零日期或不可能的日期,例如 0000‑00‑00 00:00:00,SQLite 无法存储,因此设为 NULL。 如果这些日期有意义,请在转储前于源数据中替换为真实日期。

文件在这台电脑上转换,永远不会上传。

其他示例:

从 MariaDB 到 SQLite 的变化

每一行是转换器应用的一条规则,以及该规则更改你的数据时在报告中写入的记录。

  • TINYINT(1), BOOL

    INTEGER,值保持原样

    SQLite 没有布尔类型;true 和 false 就是整数 1 和 0,因此每个值都保留其含义。

  • UNSIGNED integers

    INTEGER,并带有不能为负数的 CHECK;包含大于 2^63-1 的值的 BIGINT UNSIGNED 为 TEXT

    SQLite 整数是 64 位有符号整数。检查约束像 MySQL 一样阻止负值;超出有符号范围的值保存为文本,不丢失任何数字。

    报告记录: unsigned_widened

  • ZEROFILL and display widths

    去除

    补零只是数字的显示方式,不是数字的一部分。数字会保留;如果需要补零,请在读取时格式化。

    报告记录: zerofill_dropped

  • FLOAT(M,D)

    REAL,不带小数位数

    SQLite 的浮点数没有固定的小数位数。已存储的值按原样复制。

    报告记录: float_scale_dropped

  • DECIMAL(p,s)

    不超过 15 位时为 DECIMAL(p,s);超过则为 TEXT

    SQLite 的数字大约保留 15 位有效数字。更宽的小数保存为文本,使每一位都保持精确。

    报告记录: decimal_as_text

  • BIT(1), BIT(n)

    INTEGER,值为各位组成的数;BIT(64) 为 TEXT 数字

    位字段存储为其各位组成的数字。BIT(64) 的最高位超出有符号整数范围,因此其数字保存为文本。

  • zero, partial or impossible dates (0000-00-00, 2024-02-30)

    NULL

    SQLite 的日期函数只读取真实的日历日期。它们会变为 NULL,报告会统计其数量,与其他所有数据库相同。

    报告记录: invalid_date_null

  • NOT NULL columns with values that become NULL

    去除 NOT NULL

    值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。

    报告记录: not_null_relaxed

  • DEFAULT '0000-00-00'

    无默认值

    不是真实日期的默认值会被省略,而不是替换为编造的日期。

    报告记录: zero_date_default

  • TIME

    按 MySQL 写法的 TIME 文本,包括时长

    SQLite 以文本保存时间,因此超过一天或小于零的时长都能精确保留。

  • YEAR

    INTEGER,并带有限定范围的 CHECK

    SQLite 没有年份类型;检查约束只允许 MySQL 允许的那些值。

  • CHAR(n), VARCHAR(n)

    VARCHAR(n),不强制长度

    SQLite 保留声明的类型供工具读取,但不限制长度;值就是 MySQL 返回的值。

  • DATETIME

    DATETIME,存为 ISO 8601 文本

    SQLite 将日期存储为其日期函数能读取的文本。

  • TIMESTAMP

    TIMESTAMP,存为 UTC 的 ISO 8601 文本;使用转储声明的时区,未声明时为 UTC

    TIMESTAMP 是一个时间点,以 UTC 写入。转储会声明写入时使用的时区(mysqldump 写入 UTC);没有声明时,值按 UTC 读取,报告会说明这一点。

    报告记录: timestamp_zone_assumed

  • ENUM

    TEXT,并带有限定其值的 CHECK

    带检查约束的文本保留相同的值。

  • ENUM holding '' (MySQL's error value)

    检查约束允许的空值

    在宽松的 SQL 模式下,无效值写入 ENUM 时 MySQL 会存储空字符串。这些行会保留,检查约束允许它们。

    报告记录: enum_invalid_value

  • ENUM holding values outside its list

    不加 CHECK

    列表中没有的值会使检查失败,因此不创建检查约束。

    报告记录: enum_check_skipped

  • SET

    TEXT,按 MySQL 的写法('a,b')

    SQLite 没有数组;文本就是 MySQL 返回的文本。

  • JSON

    TEXT

    SQLite 的 JSON 函数从文本读取 JSON。声明为 JSON 的列会把 "123" 变成数字,因此使用 TEXT。

  • NUL bytes in text

    保留

    SQLite 文本可以包含 NUL 字节,因此值按原样复制。

  • text that isn't valid in its character set

    错误的字节变为替换字符

    SQLite 文本是 UTF-8;其函数会误读不是 UTF-8 的字节。

    报告记录: invalid_utf8_replaced

  • text decoded twice (ñ)

    按原样复制

    转储中存储的正是这些字符,因此按原样复制;报告会指出它们。

    报告记录: mojibake_suspected

  • AUTO_INCREMENT

    INTEGER PRIMARY KEY AUTOINCREMENT,计数器设在已复制的 id 之后

    SQLite 为完整的整数主键计数。AUTOINCREMENT 像 MySQL 一样防止 id 被重复使用,计数器从最大的 id 或转储中的 AUTO_INCREMENT 之后继续,取两者中较大者。

  • AUTO_INCREMENT on part of a key or outside one

    INTEGER,没有计数器

    SQLite 只为构成完整主键的列计数,因此该列保留其值,新行需要自行提供值。

    报告记录: identity_without_counter

  • ON UPDATE CURRENT_TIMESTAMP

    一个 AFTER UPDATE 触发器

    当行发生变化而更新语句没有设置该列时,触发器将其设为当前时间,与 MySQL 相同。

    报告记录: on_update_trigger

  • generated columns

    GENERATED ALWAYS AS,与源数据一样为 VIRTUAL 或 STORED

    SQLite 3.31 及更高版本以同样的两种方式计算生成列。

  • generated columns with functions SQLite lacks

    普通列

    无法为 SQLite 写出的公式会留下一个普通列和一条报告记录。

    报告记录: generated_not_translated

  • INVISIBLE columns

    普通列

    SQLite 没有不可见列。

    报告记录: invisible_column

  • CHECK constraints

    已转换,内联在 CREATE TABLE 中

    SQLite 只接受 CREATE TABLE 中的检查约束。

  • CHECK constraints with functions SQLite lacks

    不创建

    无法为 SQLite 写出的检查约束会被省略,并在报告中列出。

    报告记录: check_skipped

  • CHECK ... NOT ENFORCED

    不创建

    MySQL 保留这些检查约束但不执行,因此行可能违反它们。

    报告记录: check_not_enforced

  • defaults with functions SQLite lacks

    无默认值

    无法为 SQLite 写出的默认值会被省略,并在报告中列出。

    报告记录: default_not_translated

  • keys and indexes on a prefix, c(20)

    基于 substr(c, 1, 20) 的索引

    SQLite 可以为表达式建立索引,因此对相同的前缀建立索引,唯一前缀仍保持唯一。

    报告记录: prefix_unique

  • FULLTEXT indexes

    不创建

    SQLite 用单独的 FTS5 表搜索文本,需要专门的查询。

    报告记录: fulltext_not_created

  • SPATIAL indexes

    不创建

    SQLite 没有基于列的空间索引。

    报告记录: spatial_index_not_created

  • functional indexes SQLite can't write

    不创建

    基于无法为 SQLite 写出的表达式的索引会被省略,并在报告中列出。

    报告记录: index_skipped

  • foreign keys

    在 CREATE TABLE 中,不检查地导入,然后用 PRAGMA foreign_key_check 列出

    SQLite 只接受 CREATE TABLE 中的外键,并且只在 PRAGMA foreign_keys 开启时检查。行与从 MySQL 导入时一样不经检查地导入,脚本最后会列出所有没有父行的行。

  • foreign keys to columns without a unique key

    不创建

    SQLite 要求被引用的列上有唯一键;InnoDB 不要求。

    报告记录: foreign_key_skipped

  • table, index and column names

    按原样书写;仅大小写不同或索引名重复时重命名

    SQLite 名称不区分大小写,且每个数据库的索引名共用一个命名空间。

    报告记录: identifier_renamed

  • GEOMETRY, POINT, POLYGON...

    WKB,存于 BLOB

    标准的 well-known binary 格式能精确保留每个几何对象。

    报告记录: geometry_as_blob

  • INET4, INET6, UUID (MariaDB)

    TEXT

    SQLite 没有这些类型;文本就是 MariaDB 返回的文本。

  • BINARY, VARBINARY, BLOB

    BLOB

    字节仍然是字节。

  • PARTITION BY

    单个表

    行保持不变。

    报告记录: partitions_dropped

  • WITH SYSTEM VERSIONING (MariaDB)

    只含当前行的表

    转储只包含当前的行。

    报告记录: system_versioning_dropped

  • MyISAM, MEMORY and other engines

    普通表

    SQLite 只有一种表引擎。

    报告记录: engine_dropped

  • dumps of several databases

    单个文件,每个表名前加上其数据库名

    一个 SQLite 文件就是一个数据库,因此用数据库名区分同名的表。

    报告记录: databases_merged

  • views, triggers, procedures, functions and events

    在报告中列出

    它们的代码用 MySQL 的语言编写,因此会列出来,由你重新创建。

    报告记录: not_converted_objects

  • dumps without CREATE TABLE

    根据值推断类型

    使用 --no-create-info 生成的转储只有行,因此类型来自值。

    报告记录: no_schema

  • geometries in a dump without CREATE TABLE

    WKB,存于 BLOB

    MySQL 的几何格式根据值识别,并存储为标准 WKB。

    报告记录: geometry_as_blob

  • _ci collations

    精确比较

    除非另有指定,SQLite 会精确比较文本,其 NOCASE 也只对 ASCII 字母忽略大小写。

    报告记录: case_insensitive_collation

  • SET NAMES utf8 from utf8mb4 tables

    已转换,并给出警告

    MySQL 5.x 的 mysqldump 默认写出 3 字节 utf8,在任何转换器看到文件之前就已把每个 emoji 替换为问号。

    报告记录: dump_lost_four_byte_chars

  • dumps without SET NAMES whose text isn't UTF-8

    按 Latin-1 (Windows-1252) 读取

    MySQL 的 latin1 就是 Windows-1252,这是此类转储常用的编码。

    报告记录: charset_guessed

  • sjis, cp932, gbk, big5 dumps

    按 UTF-8 读取,并给出警告

    这些编码暂时无法解码。

    报告记录: unsupported_charset

  • UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows

    求值

    有些转储工具把值写成这些函数调用;它们按其产生的值读取,地理 WKT 会转为经度在前。

  • other expressions in rows

    NULL

    不运行数据库的转换器无法对它们求值。

    报告记录: expression_value

  • DEFAULT in VALUES

    该列的默认值

    字面量默认值会复制到该行中。

    报告记录: default_keyword_filled

  • DEFAULT in VALUES without a literal default

    NULL

    没有可复制的值。

    报告记录: default_keyword_null

  • REPLACE and INSERT IGNORE

    普通行

    转储中每个键只有一行,因此行是相同的。

    报告记录: replace_as_insert

  • types IntoSQL doesn't know

    TEXT

    文本可以容纳任何值;请在导入后更改类型。

    报告记录: unknown_type

  • values that don't fit their column

    NULL

    损坏或手写的转储可能包含列无法容纳的值;这些值变为 NULL,以便其余数据能够导入。

    报告记录: invalid_value_null

  • unreadable geometries

    NULL

    不是几何数据的字节无法作为几何数据存储。

    报告记录: bad_geometry

  • CREATE SEQUENCE (MariaDB)

    不创建

    SQLite 没有序列。

    报告记录: sequence_not_converted

  • VECTOR(n) (MariaDB 11.7+)

    TEXT,浮点数存为 JSON 数组

    SQLite 没有向量类型;JSON 数组保留每个浮点数。

    报告记录: type_replaced

在 MariaDB 中在 SQLite 中报告记录
TINYINT(1), BOOLINTEGER,值保持原样SQLite 没有布尔类型;true 和 false 就是整数 1 和 0,因此每个值都保留其含义。
UNSIGNED integersINTEGER,并带有不能为负数的 CHECK;包含大于 2^63-1 的值的 BIGINT UNSIGNED 为 TEXTSQLite 整数是 64 位有符号整数。检查约束像 MySQL 一样阻止负值;超出有符号范围的值保存为文本,不丢失任何数字。unsigned_widened
ZEROFILL and display widths去除补零只是数字的显示方式,不是数字的一部分。数字会保留;如果需要补零,请在读取时格式化。zerofill_dropped
FLOAT(M,D)REAL,不带小数位数SQLite 的浮点数没有固定的小数位数。已存储的值按原样复制。float_scale_dropped
DECIMAL(p,s)不超过 15 位时为 DECIMAL(p,s);超过则为 TEXTSQLite 的数字大约保留 15 位有效数字。更宽的小数保存为文本,使每一位都保持精确。decimal_as_text
BIT(1), BIT(n)INTEGER,值为各位组成的数;BIT(64) 为 TEXT 数字位字段存储为其各位组成的数字。BIT(64) 的最高位超出有符号整数范围,因此其数字保存为文本。
zero, partial or impossible dates (0000-00-00, 2024-02-30)NULLSQLite 的日期函数只读取真实的日历日期。它们会变为 NULL,报告会统计其数量,与其他所有数据库相同。invalid_date_null
NOT NULL columns with values that become NULL去除 NOT NULL值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。not_null_relaxed
DEFAULT '0000-00-00'无默认值不是真实日期的默认值会被省略,而不是替换为编造的日期。zero_date_default
TIME按 MySQL 写法的 TIME 文本,包括时长SQLite 以文本保存时间,因此超过一天或小于零的时长都能精确保留。
YEARINTEGER,并带有限定范围的 CHECKSQLite 没有年份类型;检查约束只允许 MySQL 允许的那些值。
CHAR(n), VARCHAR(n)VARCHAR(n),不强制长度SQLite 保留声明的类型供工具读取,但不限制长度;值就是 MySQL 返回的值。
DATETIMEDATETIME,存为 ISO 8601 文本SQLite 将日期存储为其日期函数能读取的文本。
TIMESTAMPTIMESTAMP,存为 UTC 的 ISO 8601 文本;使用转储声明的时区,未声明时为 UTCTIMESTAMP 是一个时间点,以 UTC 写入。转储会声明写入时使用的时区(mysqldump 写入 UTC);没有声明时,值按 UTC 读取,报告会说明这一点。timestamp_zone_assumed
ENUMTEXT,并带有限定其值的 CHECK带检查约束的文本保留相同的值。
ENUM holding '' (MySQL's error value)检查约束允许的空值在宽松的 SQL 模式下,无效值写入 ENUM 时 MySQL 会存储空字符串。这些行会保留,检查约束允许它们。enum_invalid_value
ENUM holding values outside its list不加 CHECK列表中没有的值会使检查失败,因此不创建检查约束。enum_check_skipped
SETTEXT,按 MySQL 的写法('a,b')SQLite 没有数组;文本就是 MySQL 返回的文本。
JSONTEXTSQLite 的 JSON 函数从文本读取 JSON。声明为 JSON 的列会把 "123" 变成数字,因此使用 TEXT。
NUL bytes in text保留SQLite 文本可以包含 NUL 字节,因此值按原样复制。
text that isn't valid in its character set错误的字节变为替换字符SQLite 文本是 UTF-8;其函数会误读不是 UTF-8 的字节。invalid_utf8_replaced
text decoded twice (ñ)按原样复制转储中存储的正是这些字符,因此按原样复制;报告会指出它们。mojibake_suspected
AUTO_INCREMENTINTEGER PRIMARY KEY AUTOINCREMENT,计数器设在已复制的 id 之后SQLite 为完整的整数主键计数。AUTOINCREMENT 像 MySQL 一样防止 id 被重复使用,计数器从最大的 id 或转储中的 AUTO_INCREMENT 之后继续,取两者中较大者。
AUTO_INCREMENT on part of a key or outside oneINTEGER,没有计数器SQLite 只为构成完整主键的列计数,因此该列保留其值,新行需要自行提供值。identity_without_counter
ON UPDATE CURRENT_TIMESTAMP一个 AFTER UPDATE 触发器当行发生变化而更新语句没有设置该列时,触发器将其设为当前时间,与 MySQL 相同。on_update_trigger
generated columnsGENERATED ALWAYS AS,与源数据一样为 VIRTUAL 或 STOREDSQLite 3.31 及更高版本以同样的两种方式计算生成列。
generated columns with functions SQLite lacks普通列无法为 SQLite 写出的公式会留下一个普通列和一条报告记录。generated_not_translated
INVISIBLE columns普通列SQLite 没有不可见列。invisible_column
CHECK constraints已转换,内联在 CREATE TABLE 中SQLite 只接受 CREATE TABLE 中的检查约束。
CHECK constraints with functions SQLite lacks不创建无法为 SQLite 写出的检查约束会被省略,并在报告中列出。check_skipped
CHECK ... NOT ENFORCED不创建MySQL 保留这些检查约束但不执行,因此行可能违反它们。check_not_enforced
defaults with functions SQLite lacks无默认值无法为 SQLite 写出的默认值会被省略,并在报告中列出。default_not_translated
keys and indexes on a prefix, c(20)基于 substr(c, 1, 20) 的索引SQLite 可以为表达式建立索引,因此对相同的前缀建立索引,唯一前缀仍保持唯一。prefix_unique
FULLTEXT indexes不创建SQLite 用单独的 FTS5 表搜索文本,需要专门的查询。fulltext_not_created
SPATIAL indexes不创建SQLite 没有基于列的空间索引。spatial_index_not_created
functional indexes SQLite can't write不创建基于无法为 SQLite 写出的表达式的索引会被省略,并在报告中列出。index_skipped
foreign keys在 CREATE TABLE 中,不检查地导入,然后用 PRAGMA foreign_key_check 列出SQLite 只接受 CREATE TABLE 中的外键,并且只在 PRAGMA foreign_keys 开启时检查。行与从 MySQL 导入时一样不经检查地导入,脚本最后会列出所有没有父行的行。
foreign keys to columns without a unique key不创建SQLite 要求被引用的列上有唯一键;InnoDB 不要求。foreign_key_skipped
table, index and column names按原样书写;仅大小写不同或索引名重复时重命名SQLite 名称不区分大小写,且每个数据库的索引名共用一个命名空间。identifier_renamed
GEOMETRY, POINT, POLYGON...WKB,存于 BLOB标准的 well-known binary 格式能精确保留每个几何对象。geometry_as_blob
INET4, INET6, UUID (MariaDB)TEXTSQLite 没有这些类型;文本就是 MariaDB 返回的文本。
BINARY, VARBINARY, BLOBBLOB字节仍然是字节。
PARTITION BY单个表行保持不变。partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)只含当前行的表转储只包含当前的行。system_versioning_dropped
MyISAM, MEMORY and other engines普通表SQLite 只有一种表引擎。engine_dropped
dumps of several databases单个文件,每个表名前加上其数据库名一个 SQLite 文件就是一个数据库,因此用数据库名区分同名的表。databases_merged
views, triggers, procedures, functions and events在报告中列出它们的代码用 MySQL 的语言编写,因此会列出来,由你重新创建。not_converted_objects
dumps without CREATE TABLE根据值推断类型使用 --no-create-info 生成的转储只有行,因此类型来自值。no_schema
geometries in a dump without CREATE TABLEWKB,存于 BLOBMySQL 的几何格式根据值识别,并存储为标准 WKB。geometry_as_blob
_ci collations精确比较除非另有指定,SQLite 会精确比较文本,其 NOCASE 也只对 ASCII 字母忽略大小写。case_insensitive_collation
SET NAMES utf8 from utf8mb4 tables已转换,并给出警告MySQL 5.x 的 mysqldump 默认写出 3 字节 utf8,在任何转换器看到文件之前就已把每个 emoji 替换为问号。dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8按 Latin-1 (Windows-1252) 读取MySQL 的 latin1 就是 Windows-1252,这是此类转储常用的编码。charset_guessed
sjis, cp932, gbk, big5 dumps按 UTF-8 读取,并给出警告这些编码暂时无法解码。unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows求值有些转储工具把值写成这些函数调用;它们按其产生的值读取,地理 WKT 会转为经度在前。
other expressions in rowsNULL不运行数据库的转换器无法对它们求值。expression_value
DEFAULT in VALUES该列的默认值字面量默认值会复制到该行中。default_keyword_filled
DEFAULT in VALUES without a literal defaultNULL没有可复制的值。default_keyword_null
REPLACE and INSERT IGNORE普通行转储中每个键只有一行,因此行是相同的。replace_as_insert
types IntoSQL doesn't knowTEXT文本可以容纳任何值;请在导入后更改类型。unknown_type
values that don't fit their columnNULL损坏或手写的转储可能包含列无法容纳的值;这些值变为 NULL,以便其余数据能够导入。invalid_value_null
unreadable geometriesNULL不是几何数据的字节无法作为几何数据存储。bad_geometry
CREATE SEQUENCE (MariaDB)不创建SQLite 没有序列。sequence_not_converted
VECTOR(n) (MariaDB 11.7+)TEXT,浮点数存为 JSON 数组SQLite 没有向量类型;JSON 数组保留每个浮点数。type_replaced

将脚本导入 SQLite

脚本先创建表、复制行,再添加键、索引和外键,因此导入速度快,并会在遇到第一个错误时停止。

sqlite3 -bail mydb.sqlite < mariadb.sqlite.sql

外键在每个表中声明,行在关闭外键检查的情况下导入。随后脚本会列出所有指向不存在的行的行,而不是中途失败。

对于较大的转储,请导入到本地磁盘上的新文件中。脚本在关闭同步的单个事务中导入全部内容,因此以磁盘速度运行,中途停止的导入也不会留下不完整的表。

命令行可将文件直接导入 SQLite 数据库,无需生成脚本,而且免费。

如何转储 MariaDB 以获得最佳结果

转换器读取转储中的内容。以下选项能让转储保留更多数据:

  • --default-character-set=utf8mb4 会保留表情符号和其他 4 字节字符,而 utf8mb3 转储在转换器读取之前就会丢失它们。
  • --hex-blob 将二进制列和 VECTOR 值写为十六进制,在系统之间复制时不会损坏。
  • --routines --triggers --events 会将这些对象加入转储,以便报告列出它们。

哪些内容不会转换

视图、触发器、存储过程、函数和事件都是用 MariaDB 自己的语言编写的。它们会按名称在报告中列出,绝不会被悄悄丢弃,以便你为 SQLite 重写。

关于 MariaDB 转 SQLite 的问题

这里没有你要的答案?请通过联系页面给我们留言,会有专人回复。 联系页面

我的转储会被上传吗?

不会。转换器在你的浏览器中运行,分块从磁盘读取转储,因此转储不会离开你的电脑。桌面应用和命令行也在你的电脑上转换。

转储可以多大?

转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 GB 的转储可以在浏览器、桌面应用和命令行中转换。

转储可以来自哪些 MariaDB 版本?

由 MariaDB 10.3 到 12 的 mariadb-dump 和 mysqldump 写出的转储,每个表一条 INSERT 或每行一条均可。每个测试转储都来自 MariaDB 10.11、11.4 和 11.8,并与其源数据逐个单元格比较。

UUID、INET6、JSON 和 VECTOR 列会保留吗?

UUID 和 INET 列变为 text,JSON 变为 text,VECTOR 变为由其浮点数组成的 JSON 数组。零日期变为 NULL,报告会统计其数量。

AUTO_INCREMENT 值和序列会保留吗?

构成表的完整主键的 AUTO_INCREMENT 列变为 INTEGER PRIMARY KEY AUTOINCREMENT,从最大的 id 之后继续。SQLite 没有序列,因此序列会在报告中说明。

存储过程和触发器怎么处理?

它们会按名称在报告中列出,但不会转换,因为每种数据库都用自己的语言编写它们。

脚本可以导入哪些 SQLite 版本?

SQLite 3.31 及更高版本。每个测试转储都能在 3.31 和 3.54 上导入,如有问题会在第一个错误处停止。