⌘+k ctrl+k
1.1.3 (stable)
Search Shortcut cmd + k | ctrl + k
SQLite Extension

SQLite 扩展允许 DuckDB 直接从 SQLite 数据库文件中读取和写入数据。可以直接从底层的 SQLite 表中查询数据。数据可以从 SQLite 表加载到 DuckDB 表中,反之亦然。

安装和加载

sqlite 扩展将在首次使用时从官方扩展仓库中自动加载。 如果您想手动安装和加载它,请运行:

INSTALL sqlite;
LOAD sqlite;

Usage

为了使SQLite文件对DuckDB可访问,使用带有SQLITESQLITE_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的类型亲和规则,并有一些扩展。

  1. 如果声明的类型包含字符串 INT,则它会被转换为类型 BIGINT
  2. 如果列的声明类型包含任何字符串CHARCLOBTEXT,则它会被转换为VARCHAR
  3. 如果列的声明类型包含字符串BLOB或者未指定类型,则将其转换为BLOB
  4. 如果列的声明类型包含以下任意字符串 REAL, FLOA, DOUB, DECNUM,则它会被转换为 DOUBLE
  5. 如果声明的类型是DATE,那么它会被转换为DATE
  6. 如果声明的类型包含字符串TIME,则它会被转换为TIMESTAMP
  7. 如果以上情况均不适用,则将其翻译为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 语法