如何将 JSON 文件转换为 SQLite 数据库

How to convert a JSON file to an SQLite database

如果我有一些示例数据,如何将其放入 SQLite(最好是全自动的)?

{"uri":"/","user_agent":"example1"}
{"uri":"/foobar","user_agent":"example1"}
{"uri":"/","user_agent":"example2"}
{"uri":"/foobar","user_agent":"example3"}

我发现最简单的方法是使用 jq 和 CSV 作为中间格式。

编辑: 正如所指出的(感谢 @Leo), the original question did show newline delimited JSON objects, which each on their own conform to rfc4627,但不是所有的格式都在一起。 jq 可以处理 objects 的单个 JSON 数组,尽管通过使用 jq '.[]' <input.json >preprocessed.json 预处理文件,方法与此大致相同。 如果您碰巧正在处理 JSON 文本序列 (rfc7464),幸运的是 jq 也通过 --seq 参数支持了您。

编辑 2: 换行分隔 JSON 和 JSON 文本序列都有一个重要的优点;它们将内存需求降低到 O(1),这意味着您的总内存需求仅取决于您最长的输入行,而将整个输入放在一个数组中需要您的解析器可以处理后期错误(即在第一个 100k 之后元素有语法错误),据我所知通常不是这种情况,或者它必须解析整个文件两次(首先验证语法,然后解析,在丢弃先前元素的过程中,就像 jq --stream) 这在我看来也很少发生,或者它会尝试一次解析整个输入并一步 return 结果(想想接收一个 Python dict 其中包含整个你说的 50G 输入数据加上开销)通常是内存支持的,因此你的内存占用量增加了你的总数据大小。

编辑 3: 如果遇到任何障碍,请尝试使用 keys_unsorted 而不是 keys。 我自己还没有测试过(我假设我的列已经排序),但是 @Kyle Barron reports that this was needed.

获取 CSV

首先将数据写入文件。 我将在这里假设 data.json

然后构造 header 使用 jq:

% head -1 data.json | jq -r 'keys | @csv'
"uri","user_agent"

head -1是因为我们只想要一行。 jq-r 使输出成为纯字符串而不是 JSON-String 包装 CSV。 然后我们调用内部函数 keys 将输入的键作为数组获取。 我们将其发送到 @csv 格式化程序,后者以引用的 CSV 格式向我们输出一个带有 header 的字符串。

然后我们需要构建数据。

% jq -r '[.[]] | @csv' < data.json
"/","example1"
"/foobar","example1"
"/","example2"
"/foobar","example3"

我们现在获取整个输入并使用 .[] 解构关联数组(映射),然后将其放回简单数组 […]。 这基本上将我们的字典转换为键数组。 发送到 @csv 格式化程序,我们再次获得一些 CSV。

将所有内容放在一起,我们得到一个 one-liner,其形式为:

% (head -1 data.json | jq -r 'keys | @csv' && jq -r '[.[]] | @csv' < data.json) > data.csv

如果您需要即时转换数据,即没有文件,试试这个:

% cat data.json | (read -r first && jq -r '(keys | @csv),( [.[]] | @csv)' <<<"${first}" && jq -r '[.[]] | @csv')

正在将其加载到 SQLite 中

打开 SQLite 数据库:

sqlite3 somedb.sqlite

现在在交互式 shell 中执行以下操作(假设您将 CSV 写入 data.csv 并希望在 table 中调用my_table):

.mode csv
.import data.csv my_table

现在关闭 shell 并再次打开它以获得干净的环境。 您现在可以轻松 SELECT 从数据库中进行任何您想做的事情。

综合起来

asciinema 录音:

sqlitebiter 似乎提供了 python 解决方案:

将 CSV/Excel/HTML/JSON/LTSV/Markdown/SQLite/TSV/Google-Sheets 转换为 SQLite 数据库文件的 CLI 工具。 http://sqlitebiter.rtfd.io/

文档: http://sqlitebiter.readthedocs.io/en/latest/

项目: https://github.com/thombashi/sqlitebiter

  • 上次更新大约 3 个月前
  • 上一期大约 1 个月前关闭,none 打开
  • 今天注意到,2018-03-14

无需 CSV 或第 3 方工具 的方法是使用 sqlite3 CLI 工具中提供的 JSON1 extension of SQLite combined with the readfile extension

如果输入文件是格式正确的 JSON 文件,例如作为数组给出的示例:

[
{"uri":"/","user_agent":"example1"},
{"uri":"/foobar","user_agent":"example1"},
{"uri":"/","user_agent":"example2"},
{"uri":"/foobar","user_agent":"example3"}
]

那么这个可以读入对应的my_table table如下。使用 sqlite3 CLI 打开 SQLite 数据库文件 my_db.db:

sqlite3 my_db.db

然后创建 my_table 使用:

CREATE TABLE my_table(uri TEXT, user_agent TEXT);

最后,my_data.json中的JSON数据可以用CLI命令插入到table中:

INSERT INTO my_table SELECT 
  json_extract(value, '$.uri'), 
  json_extract(value, '$.user_agent')
FROM json_each(readfile('my_data.json'));

除了总体上是一个“更直接”的解决方案外,它还具有处理 JSON NULL 值比 CSV 更一致的优势,否则 CSV 会将它们导入为空字符串。

如果初始 JSON 文件是换行符分隔的 JSON 元素,则可以先使用 jq 转换:

jq -s <my_data_raw.json >my_data.json

可能有一种方法可以使用 JSON1 在 SQLite 中直接执行此操作,但鉴于我已经在使用 jq 进行按摩,我没有继续这样做导入 SQLite 之前的数据。

您可以使用 spyql。 spyql 读取 json 文件(每行 1 个 json 对象)并生成 INSERT 语句,您可以通过管道将其导入 sqlite:

$ spyql -Otable=my_table "SELECT json->uri, json->user_agent FROM json TO sql" < sample3.json | sqlite3 my.db

这假设您已经在 sqlite 数据库 my.db 中创建了一个空的 table。

免责声明:我是spyql的作者。