SQLite 扩展允许 DuckDB 直接从 SQLite 数据库文件读取和写入数据。数据可以直接从底层的 SQLite 表中查询。数据可以从 SQLite 表加载到 DuckDB 表中,反之亦然。
安装和加载
sqlite
扩展在首次使用时将从官方扩展仓库透明地自动加载。如果您想手动安装和加载它,请运行
INSTALL sqlite;
LOAD sqlite;
用法
要使 SQLite 文件可供 DuckDB 访问,请使用带有 sqlite
或 sqlite_scanner
类型的 ATTACH
语句。附加的 SQLite 数据库支持读写操作。
例如,要附加到 sakila.db
文件,请运行
ATTACH 'sakila.db' (TYPE sqlite);
USE sakila;
文件中的表可以像普通 DuckDB 表一样读取,但底层数据在查询时直接从文件中的 SQLite 表中读取。
SHOW TABLES;
name |
---|
actor |
address |
category |
城市 |
国家 |
customer |
customer_list |
film |
film_actor |
film_category |
film_list |
film_text |
inventory |
language |
payment |
rental |
sales_by_film_category |
sales_by_store |
staff |
staff_list |
store |
您可以使用 SQL 查询表,例如,使用 sakila-examples.sql
中的示例查询
SELECT
cat.name AS category_name,
sum(ifnull(pay.amount, 0)) AS revenue
FROM category cat
LEFT JOIN film_category flm_cat
ON cat.category_id = flm_cat.category_id
LEFT JOIN film fil
ON flm_cat.film_id = fil.film_id
LEFT JOIN inventory inv
ON fil.film_id = inv.film_id
LEFT JOIN rental ren
ON inv.inventory_id = ren.inventory_id
LEFT JOIN payment pay
ON ren.rental_id = pay.rental_id
GROUP BY cat.name
ORDER BY revenue DESC
LIMIT 5;
数据类型
SQLite 是一个弱类型数据库系统。因此,在 SQLite 表中存储数据时,不强制执行类型。以下是 SQLite 中有效的 SQL:
CREATE TABLE numbers (i INTEGER);
INSERT INTO numbers VALUES ('hello');
DuckDB 是一个强类型数据库系统,因此它要求所有列都具有定义的类型,并且系统严格检查数据的正确性。
在查询 SQLite 时,DuckDB 必须推断出特定的列类型映射。DuckDB 遵循 SQLite 的类型亲和规则,并进行了一些扩展。
- 如果声明的类型包含字符串
INT
,则将其转换为类型BIGINT
- 如果列的声明类型包含字符串
CHAR
、CLOB
或TEXT
中的任何一个,则将其转换为VARCHAR
。 - 如果列的声明类型包含字符串
BLOB
,或者未指定类型,则将其转换为BLOB
。 - 如果列的声明类型包含字符串
REAL
、FLOA
、DOUB
、DEC
或NUM
中的任何一个,则将其转换为DOUBLE
。 - 如果声明的类型是
DATE
,则将其转换为DATE
。 - 如果声明的类型包含字符串
TIME
,则将其转换为TIMESTAMP
。 - 如果以上都不适用,则将其转换为
VARCHAR
。
由于 DuckDB 强制相应列只包含正确类型的值,我们无法将字符串“hello”加载到 BIGINT
类型的列中。因此,当从上面的“numbers”表中读取时会抛出错误
Mismatch Type Error: Invalid type in column "i": column was declared as integer, found "hello" of type "text" instead.
可以通过设置 sqlite_all_varchar
选项来避免此错误
SET GLOBAL sqlite_all_varchar = true;
设置后,此选项将覆盖上述类型转换规则,而是始终将 SQLite 列转换为 VARCHAR
列。请注意,此设置必须在调用 sqlite_attach
之前进行。
直接打开 SQLite 数据库
SQLite 数据库也可以直接打开,并且可以透明地代替 DuckDB 数据库文件使用。在任何客户端连接时,都可以提供 SQLite 数据库文件的路径,然后将打开 SQLite 数据库。
例如,在 shell 中,SQLite 数据库可以按如下方式打开
duckdb sakila.db
SELECT first_name
FROM actor
LIMIT 3;
first_name |
---|
PENELOPE |
NICK |
ED |
向 SQLite 写入数据
除了从 SQLite 读取数据外,该扩展还允许您使用标准 SQL 查询创建新的 SQLite 数据库文件、创建表、将数据导入 SQLite 并对 SQLite 数据库文件进行其他修改。
这允许您使用 DuckDB,例如,将存储在 SQLite 数据库中的数据导出到 Parquet,或者将 Parquet 文件中的数据读取到 SQLite 中。
以下是关于如何创建新的 SQLite 数据库并向其中加载数据的简要示例。
ATTACH 'new_sqlite_database.db' AS sqlite_db (TYPE sqlite);
CREATE TABLE sqlite_db.tbl (id INTEGER, name VARCHAR);
INSERT INTO sqlite_db.tbl VALUES (42, 'DuckDB');
然后可以从 SQLite 中读取生成的 SQLite 数据库。
sqlite3 new_sqlite_database.db
SQLite version 3.39.5 2022-10-14 20:58:05
sqlite> SELECT * FROM tbl;
id name
-- ------
42 DuckDB
支持对 SQLite 表进行许多操作。所有这些操作都直接修改 SQLite 数据库,后续操作的结果可以使用 SQLite 读取。
并发
当 DuckDB 或 SQLite 从不同的线程或单独的进程读写同一数据库时,DuckDB 可以读写 SQLite 数据库。多个线程或进程可以同时读取 SQLite 数据库,但每次只能有一个线程或进程写入数据库。数据库锁定由 SQLite 库处理,而不是 DuckDB。在同一进程内,SQLite 使用互斥锁。从不同进程访问时,SQLite 使用文件系统锁。锁定机制也取决于 SQLite 配置,如 WAL 模式。有关更多信息,请参阅SQLite 锁定文档。
警告:将多个 SQLite 库副本链接到同一个应用程序可能会导致应用程序错误。有关更多信息,请参阅sqlite_scanner 问题 #82。
设置
该扩展公开了以下配置参数。
名称 | 描述 | 默认值 |
---|---|---|
sqlite_debug_show_queries |
调试设置:将所有发送到 SQLite 的查询打印到标准输出 | false |
支持的操作
以下是支持的操作列表。
CREATE TABLE
CREATE TABLE sqlite_db.tbl (id INTEGER, name VARCHAR);
INSERT INTO
INSERT INTO sqlite_db.tbl VALUES (42, 'DuckDB');
SELECT
SELECT * FROM sqlite_db.tbl;
id | name |
---|---|
42 | DuckDB |
COPY
COPY sqlite_db.tbl TO 'data.parquet';
COPY sqlite_db.tbl FROM 'data.parquet';
UPDATE
UPDATE sqlite_db.tbl SET name = 'Woohoo' WHERE id = 42;
DELETE
DELETE FROM sqlite_db.tbl WHERE id = 42;
ALTER TABLE
ALTER TABLE sqlite_db.tbl ADD COLUMN k INTEGER;
DROP TABLE
DROP TABLE sqlite_db.tbl;
CREATE VIEW
CREATE VIEW sqlite_db.v1 AS SELECT 42;
事务
CREATE TABLE sqlite_db.tmp (i INTEGER);
BEGIN;
INSERT INTO sqlite_db.tmp VALUES (42);
SELECT * FROM sqlite_db.tmp;
i |
---|
42 |
ROLLBACK;
SELECT * FROM sqlite_db.tmp;
i |
---|
已废弃:旧的
sqlite_attach
函数已废弃。建议切换到新的ATTACH
语法。