跳转到内容

数据源 ​

English

DuckLocal 把文件变成视图,挂到内存中的 DuckDB 连接上;打开了数据库文件时,就挂到那个数据库文件里。旁边还可以再附加其他数据库。不需要任何配置。

打开数据的方式 ​

以下入口都走同一套解析规则:

  1. 命令行中的路径:ducklocal ./logs/ billing.parquet
  2. 标题栏的 打开 菜单:打开文件、打开文件夹,或 输入路径或通配符——后者会打开 打开数据 对话框,可以手动输入路径,也可以用系统文件选择器选取
  3. 把文件或文件夹拖到窗口的任意位置
  4. 在 Mac 上,由访达交给 DuckLocal 的文件,见从访达打开

如果想在当前数据库旁边再加一个数据库、而不是替换它,用 打开 → 附加数据库…,见附加数据库。

在 macOS 上,还可以在访达里双击打开 Parquet 和 DuckDB 文件;选中 Parquet、DuckDB、CSV、TSV 或 JSON Lines 文件按空格键,“快速查看”会显示它的前几行,不用启动 DuckLocal。

支持的文件格式 ​

扩展名不区分大小写。

扩展名读取方式
.csv, .tsv, .txtread_csv_auto 视图
.parquetread_parquet 视图
.json, .ndjson, .jsonlread_json_auto 视图
.xlsx, .xls, .xlsb, .ods每个工作表导入为一张表

.json.gz、.csv.gz 这类 gzip 文本也算数据文件,适用于 schema、source block 和挂载文件;logs.json.gz 会成为名为 logs 的视图。0.4.0 之前,ducklocal schema 会把这种文件当作数据库尝试打开;如果你用的是旧版,请在 SQL 里用 read_json 或 read_csv 读取。

其他扩展名都不算数据文件,参见数据库文件。

工作簿是唯一会转换为表而非视图的格式,并且会导入所有工作表。第一个工作表以文件名主干(去掉扩展名的部分)命名,其余工作表命名为 {主干}_{工作表名},空工作表会跳过。列类型根据单元格内容推断:整数为 BIGINT,整数与浮点数混合为 DOUBLE,日期为 TIMESTAMP,其他混合或无法识别的内容为 VARCHAR;空单元格导入为 NULL。

文件夹与通配符 ​

文件夹会递归遍历,其中每个数据文件都变成一个视图。遍历遵循两条规则:

  • 跳过隐藏条目(名字以 . 开头),也不进入其下的子目录。
  • 不跟随符号链接。指向上层目录的链接会让遍历没完没了;而链接指向的目录,通常会在它实际所在的位置遍历到。

文件按排序后的顺序挂载,所以同一个文件夹每次得到的工作区都一样。

通配符可以包含 *(任意一串字符)和 ?(恰好一个字符)。匹配按路径逐段、直接在文件系统上进行,所以通配符可以跨目录:

bash
ducklocal './data/2026-0*/*.parquet'

没有转义字符。** 没有特殊含义,效果和单个 * 一样,不会递归。通配符匹配到的目录会被忽略,只挂载文件。这里同样跳过隐藏条目。

不加引号的通配符会先由 shell 展开,DuckLocal 拿到的是展开后的结果。这样没问题。只有想让 DuckLocal 自己展开时才需要加引号——比如 shell 匹配不到文件、不加引号就会报错的情况。

一次读取多个 CSV ​

DuckLocal 挂载的每个文件都是独立的视图,schema 各自嗅探,所以两个结构不一致的 CSV 互不干扰。麻烦出在一条 SQL 同时读取多个文件的时候:

sql
SELECT * FROM read_csv('data/*.csv', union_by_name = true)
  • 各文件嗅探出的类型可能对不上。 读取函数根据样本推断列类型。某列在其他文件里都是数值,只在一个文件里混进了字符串 'NULL',整个读取就会报转换错误。这时在 SELECT 里做 cast 已经来不及,因为出错的是读取这一步。应该把所有列按文本读入,再在 SQL 里转换:

    sql
    SELECT try_cast(amount AS DOUBLE) AS amount
    FROM read_csv('data/*.csv', union_by_name = true, all_varchar = true)

    union_by_name = true 还能兼容列不完全相同的文件。

  • 字符串 'NULL' 不是 NULL。 CSV 里写着的 'NULL'(或 'N/A'、'null')只是普通文本,WHERE amount IS NOT NULL 过滤不掉。可以用 NULLIF(amount, 'NULL'),或者 WHERE amount <> 'NULL'。

两种修法可以叠加:try_cast(NULLIF(amount, 'NULL') AS DOUBLE)。

数据库文件 ​

DuckLocal 同一时间只有一个主数据库:要么在内存里,要么是你打开的 DuckDB 文件。数据文件变成主数据库里的视图。此外还可以在旁边附加其他数据库。

只要路径存在且不是数据文件,就会作为主数据库打开,不会挂载成视图。扩展名无所谓:.db、.duckdb,甚至 .md 路径都会当作数据库,能不能真正打开由 DuckDB 决定。

由此有几点需要知道:

  • 只有“打开数据”对话框能新建数据库。 输入一个以 .duckdb 结尾、还不存在的路径,DuckLocal 会创建这个数据库,缺少的父目录也一并创建。其他入口——命令行、文件选择器、拖放、访达——遇到不存在的路径都会报 文件不存在。
  • 打开数据库会替换主数据库。 已登记的文件和附加的数据库会重新挂到新连接上。S3 凭据不会保留,需要重新配置。
  • 文件打不开时,DuckLocal 会说明原因(见下文)。启动时它会退回内存模式的工作区,不会启动失败;运行期间打开失败,原来的工作区保持不变。
  • 已经附加在主数据库旁边的文件,会先分离,再作为主数据库打开;打开失败的话,附加会恢复原样。打开的正是当前主数据库文件时,直接沿用,不会重复打开。

打开数据库文件后再挂载数据文件,会把这些视图写进那个数据库文件,视图会一直保存在那里,不只存在于本次会话。

数据库文件打不开时 ​

DuckDB 拒绝打开某个文件时,DuckLocal 会自己读取文件开头的几个字节;如果能从中看出原因,就把原因和解决办法放在 DuckDB 原始报错的上方。DuckDB 的原始报错保留在下面,方便查看确切错误。说明文字跟随界面语言。

文件是什么DuckLocal 的说明
由比 DuckLocal 内置版本更新的 DuckDB 写入的 DuckDB 文件写明两个版本号,并给出一段 SQL,在那个较新的 DuckDB 里运行,把文件复制成 DuckLocal 能读的格式(见下)
来自 v0.9 或更早版本的 DuckDB 文件用原来的 DuckDB 执行 EXPORT DATABASE 'dir',再在 DuckLocal 里执行 IMPORT DATABASE 'dir'
SQLite 数据库它不是 DuckDB 文件,应该附加它——用附加数据库…,或者 INSTALL sqlite; ATTACH '…' (TYPE sqlite);
其他不是 DuckDB 文件的东西CSV、Parquet、JSON、Excel 文件请作为数据文件打开

对于较新 DuckDB 写的文件,提示里会填好文件路径和 DuckLocal 内置的 DuckDB 版本。在创建该文件的那个 DuckDB 里运行,然后打开 compat.duckdb:

sql
ATTACH '/path/to/file.duckdb' AS src (READ_ONLY);
ATTACH 'compat.duckdb' AS dst (STORAGE_VERSION 'v2.0.0');
COPY FROM DATABASE src TO dst;

DuckDB v1.2 之前写入的文件不记录是哪个版本创建的。其他原因的失败——文件被别的程序锁住、没有读取权限等——只显示 DuckDB 的原始报错。参见常见问题排查。

哪些 DuckDB 能读这个数据库 ​

打开数据库文件后,状态栏会显示它的路径。把鼠标悬停在上面,可以看到文件的存储格式,也就是能读它的最低 DuckDB 版本,例如 存储格式:DuckDB v1.0.0+ 可读;文件里有记录时,还会显示创建它的版本(由 DuckDB v1.4.3 创建)。把文件交给使用旧版 DuckDB 的人之前,先看一眼这里。

DuckLocal 用的是 DuckDB 2.0,但它新建的数据库文件按 DuckDB 1.x 的格式写入(DuckDB v1.0.0+ 可读),所以 DuckDB 1.x 的命令行、Python 或 DBeaver 仍然能打开。其他程序按 DuckDB 2.0 自己的格式(v2.0.0+)写的文件也能打开,并保持原格式:1.x 读不了这种文件。

附加数据库 ​

把另一个 DuckDB 或 SQLite 文件附加在主数据库旁边,就能跨库查询——比如把一份快照和今天的数据放在一起比。

  1. 打开标题栏的 打开 菜单,选择 附加数据库…。
  2. 输入路径,或点击 浏览 选择文件。
  3. 除非确实要修改这个文件,否则保持勾选 只读。它默认是勾选的。
  4. 点击 附加。

数据库会根据文件名得到一个别名,用 别名.表(或 别名.schema.表)查询其中的表:

sql
-- snap-2026-10-01.duckdb 附加后的别名是 snap_2026_10_01
SELECT t.id, t.amount, s.amount AS amount_last_week
FROM orders t
JOIN snap_2026_10_01.orders s USING (id);

别名的生成规则:

  • 取文件名主干,其中不是 ASCII 字母或数字的字符都换成 _。
  • 不以字母开头时,前面加 db_:2026-10 logs.duckdb 变成 db_2026_10_logs。
  • 名字已被占用时加序号:snap,然后是 snap_2。不会使用 main。
  • 以后再次附加同一个文件,会拿回它原来的别名,针对它写好的 SQL 照样能跑。

其他细节:

  • SQLite 文件根据文件内容识别,通过 DuckDB 的 sqlite 扩展附加。
  • **取消勾选“只读”**会以可写方式附加。这时如果 DuckDB 路径不存在,会新建一个空数据库;勾选只读时,附加会失败。
  • 同一个文件不会附加两次。 附加一个已经打开的文件(不论它是主数据库还是已附加的数据库),会提示 这个数据库已经打开了,名为 …。

在侧栏中 ​

所有数据库都出现在 schema 树里,主数据库和附加的数据库一样,空数据库也列出。数据库名旁边会视情况显示 只读 或 sqlite,鼠标悬停可看到对应的文件。

右键点击数据库:

  • 设为默认数据库——执行 USE,之后不带库名的表名都在这里查找。状态栏会显示当前在哪里查找。
  • 分离数据库——分离并忘掉它,下次不会再自动附加。如果它正是默认数据库,会先切回主数据库。文件本身不受影响。

右键菜单的其余选项见 Schema 浏览与历史。

跨连接保留 ​

附加的数据库连同别名和只读设置,存放在 DuckLocal 自己的历史数据库里,每次建立新连接时都会重新附加:下次启动时、打开另一个数据库后、以及选择 新建内存数据库 后。

  • 文件不存在的数据库会悄悄跳过。登记仍然保留,文件回来后它也会回来——DuckLocal 不会在原位置建一个空数据库。
  • 已经打开的数据库(不论是作为主数据库还是别的方式)不会再附加一次。
  • 如果新的主数据库里已经有同名的数据库,DuckLocal 会提示 无法附加 …:名称 … 已被当前数据库占用。

从访达打开 ​

在 Mac 上,访达可以直接把文件交给 DuckLocal:

文件双击“打开方式”,或拖到程序坞图标上
.parquet在 DuckLocal 中打开可以
.duckdb、.ddb在 DuckLocal 中打开可以
.dash在 DuckLocal 中打开可以
.csv、.tsv、.json、.jsonl、.ndjson、.xlsx、.xls仍由原来打开它们的应用处理(Numbers、Excel、文本编辑器)可以

DuckLocal 只把自己注册为 Mac 上没有其他应用认领的格式的默认应用。如果 Parquet 或 DuckDB 文件已经被别的应用占了,就在 打开方式 里选 DuckLocal;或者在访达里用 显示简介 → 打开方式 → 全部更改… 把它设为默认。

从访达来的文件,处理方式和拖到窗口上完全一样:数据文件变成当前工作区里的视图,数据库文件作为主数据库打开,.dash 文件作为仪表盘标签页打开。如果 DuckLocal 没在运行,会先启动,等它自己的启动流程完成后再打开这个文件。

快速查看(Quick Look)预览 ​

在 Mac 上,在访达里选中数据文件后按空格键,不用打开任何应用就能看到它的列和前几行。预览功能内置在 DuckLocal.app 里,不需要另外安装。和应用本身一样,需要 macOS 12 或更新版本。

文件预览内容
.parquet列和类型、前 50 行,以及文件尾部(footer)里的信息:行数、行组数、压缩方式、写入程序
.duckdb、.ddb表的数量、存储格式(Readable by DuckDB …),以及最大的五张表,每张表附估算行数和前 50 行
.csv、.tsv列及嗅探出的类型、前 50 行——以表格显示,而不是纯文本
.jsonl、.ndjson列和前 50 行

普通 .json 和 Excel 文件仍由 macOS 自带的预览处理。

预览会做什么、不会做什么:

  • 从不写入。数据库以只读方式附加。
  • 从不扫描整个文件:行数据用 LIMIT 读取,只有格式本身存了行数时才显示行数(Parquet 的文件尾部、数据库的估算值)。
  • 不下载任何东西:既不安装也不加载 DuckDB 扩展。
  • 超过 200 个字符的单元格会被截断。预览页面的文字是英文。
  • 读不了的文件会显示一页说明原因。

按空格键后没有出现 DuckLocal 的预览时:

  1. 确认 DuckLocal 在 应用程序 文件夹里,并启动一次。macOS 第一次见到这个应用时才会登记预览功能。
  2. 在终端里重置快速查看:qlmanage -r,然后再试一次。
  3. 在“系统设置”的扩展设置里,确认快速查看下的 DuckLocal Preview 已开启。

命名 ​

文件对应的视图以文件名主干命名,并整理成合法的标识符。名字在连接中已被占用时,DuckLocal 会加上序号:events,然后是 events_2、events_3。所以两个文件即使在不同目录、主干同名,也会得到不同的视图。

判断是否重复,看的是写出来的路径文本,所以 ./a.csv 和 a.csv 算两个不同的文件。

限制 ​

  • 每次打开最多 256 个数据文件。 上限按一次请求里的所有路径合计,不按文件夹分别计算。这样即使不小心把整个用户主目录拖进来,连接也不会被占上好几分钟。达到上限时,DuckLocal 会给出提示,只挂载前 256 个文件。
  • 启动时重新挂载上次会话的文件,不受这个上限限制。

管理已注册的数据源 ​

已注册的文件列在侧栏的本地文件分组里,每个文件显示视图名、文件名和行数。选中文件会生成一条查询它的 SELECT 语句。

点文件行上的 ×,确认后即可移除。移除会删除视图、清除这条注册;文件本身不受任何影响。

刷新 schema 会重新加载目录(catalog)和已注册的文件。

会被记住的内容 ​

已注册文件的清单(路径、视图名和类型)存放在 DuckLocal 自己的历史数据库里,下次启动时重新挂载,所以关掉时是什么工作区,再打开还是什么工作区。附加的数据库也一样。主数据库文件本身不会记住:除非指定了数据库,每次启动都从内存模式开始。

这些数据在磁盘上的位置,参见设置与应用数据。

基于 Apache-2.0 许可开源发布。