SQLite 扩展允许 DuckDB 直接从 SQLite 数据库文件中读取和写入数据。可以直接从底层的 SQLite 表中查询数据。数据可以从 SQLite 表加载到 DuckDB 表中,反之亦然。
安装和加载
sqlite
扩展将在首次使用时从官方扩展仓库中自动加载。
如果您想手动安装和加载它,请运行:
INSTALL sqlite;
LOAD sqlite;
Usage
为了使SQLite文件对DuckDB可访问,使用带有SQLITE
或SQLITE_SCANNER
类型的ATTACH
语句。附加的SQLite数据库支持读写操作。
例如,要附加到sakila.db
文件,请运行:
ATTACH 'sakila.db' (TYPE SQLITE);
USE sakila;
文件中的表可以像普通的DuckDB表一样读取,但底层数据在查询时直接从文件中的SQLite表中读取。
SHOW TABLES;
名称 |
---|
演员 |
地址 |
类别 |
城市 |
国家 |
客户 |
客户列表 |
电影 |
film_actor |
电影类别 |
film_list |
电影文本 |
库存 |
语言 |
支付 |
租赁 |
按电影类别销售 |
按商店销售 |
员工 |
员工列表 |
商店 |
您可以使用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;
名字 |
---|
佩内洛普 |
昵称 |
ED |
将数据写入SQLite
除了从SQLite读取数据外,该扩展还允许您创建新的SQLite数据库文件、创建表、将数据导入SQLite,并使用标准SQL查询对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 可以在 DuckDB 或 SQLite 从不同线程或独立进程读取或修改同一数据库时读取或修改 SQLite 数据库。多个线程或进程可以同时读取 SQLite 数据库,但一次只能有一个线程或进程写入数据库。数据库锁定由 SQLite 库处理,而不是 DuckDB。在同一进程内,SQLite 使用互斥锁。当从不同进程访问时,SQLite 使用文件系统锁。锁定机制还取决于 SQLite 配置,如 WAL 模式。有关更多信息,请参阅 SQLite 锁定文档。
警告 将多个SQLite库的副本链接到同一个应用程序中可能会导致应用程序错误。更多信息请参见sqlite_scanner Issue #82。
支持的操作
以下是支持的操作列表。
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;
编号 | 名称 |
---|---|
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
语法。