如果我有一些示例数据,如何将其放入 SQLite(最好是完全自动化的)?
{"uri":"/","user_agent":"example1"}
{"uri":"/foobar","user_agent":"example1"}
{"uri":"/","user_agent":"example2"}
{"uri":"/foobar","user_agent":"example3"}
如果我有一些示例数据,如何将其放入 SQLite(最好是完全自动化的)?
{"uri":"/","user_agent":"example1"}
{"uri":"/foobar","user_agent":"example1"}
{"uri":"/","user_agent":"example2"}
{"uri":"/foobar","user_agent":"example3"}
我发现最简单的方法是使用jq和 CSV 作为中间格式。
编辑:正如所指出的(感谢@Leo),最初的问题确实显示了换行符分隔的 JSON 对象,每个对象本身都符合rfc4627,但并非全部都以这种格式。
jq可以处理单个 JSON 对象数组,但使用jq '.[]' <input.json >preprocessed.json
. 如果您碰巧正在处理 JSON 文本序列 ( rfc7464 ),幸运的是jq也得到了您的支持--seq
。
编辑 2:换行符分隔的 JSON 和 JSON 文本序列都有一个重要的优势;它们将内存需求降低到 O(1),这意味着您的总内存需求仅取决于您最长的输入行,而将整个输入放在一个数组中要求您的解析器可以处理后期错误(即在前 100k 之后元素存在语法错误),据我所知,这通常不是这种情况,或者它必须解析整个文件两次(首先验证语法,然后解析,在这个过程中丢弃以前的元素,就像jq --stream
) 这在我的知识中也很少发生,或者它会尝试一次解析整个输入并在一步中返回结果(想想接收一个 Python 字典,其中包含你说的全部 50G 输入数据加上开销),这通常是内存支持,因此将您的内存占用量增加了大约您的总数据大小。
编辑 3:如果您遇到任何障碍,请尝试使用keys_unsorted而不是keys。我自己没有测试过(我有点假设我的列已经排序),但是@Kyle Barron报告说这是需要的。
首先将数据写入文件。我将在这里假设data.json。
然后使用构造标题jq
:
% head -1 data.json | jq -r 'keys | @csv'
"uri","user_agent"
这head -1
是因为我们只想要一条线。
jq
's-r
使输出成为纯字符串,而不是包装 CSV 的 JSON 字符串。然后我们调用内部函数keys
将输入的键作为数组获取。我们将其发送到@csv
格式化程序,该格式化程序向我们输出一个带有引号的 CSV 格式标题的字符串。
然后我们需要构建数据。
% jq -r '[.[]] | @csv' < data.json
"/","example1"
"/foobar","example1"
"/","example2"
"/foobar","example3"
我们现在获取整个输入并使用解构关联数组(映射).[]
,然后将其放回一个简单的数组[…]
中。这基本上将我们的字典转换为键数组。发送到@csv
格式化程序,我们再次得到一些 CSV。
把它们放在一起,我们得到一个单一的形式:
% (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 数据库:
sqlite3 somedb.sqlite
现在在交互式 shell 中执行以下操作(假设您将 CSV 写入data.csv并希望将其放在名为 的表中my_table
):
.mode csv
.import data.csv my_table
现在关闭外壳并再次打开它以获得干净的环境。您现在可以轻松地SELECT
从数据库中做任何您想做的事情。
在那里进行asciinema记录:
在没有 CSV 或第 3 方工具的情况下执行此操作的一种方法是使用SQLite 的扩展与 CLI 工具中提供的JSON1
扩展相结合readfile
。sqlite3
如果输入文件是格式良好的 JSON 文件,例如以数组形式给出的示例:
[
{"uri":"/","user_agent":"example1"},
{"uri":"/foobar","user_agent":"example1"},
{"uri":"/","user_agent":"example2"},
{"uri":"/foobar","user_agent":"example3"}
]
然后可以将其读入相应的my_table
表中,如下所示。my_db.db
使用 sqlite3 CLI打开 SQLite 数据库文件:
sqlite3 my_db.db
然后my_table
使用创建:
CREATE TABLE my_table(uri TEXT, user_agent TEXT);
最后,my_data.json
可以使用 CLI 命令将其中的 JSON 数据插入到表中:
INSERT INTO my_table SELECT
json_extract(value, '$.uri'),
json_extract(value, '$.user_agent')
FROM json_each(readfile('my_data.json'));
除了总体上是一个“更直接”的解决方案外,这还具有比 CSV 更一致地处理 JSON NULL 值的优势,否则会将它们作为空字符串导入。
如果初始 JSON 文件是换行符分隔的 JSON 元素,则可以首先使用以下方法进行转换jq
:
jq -s <my_data_raw.json >my_data.json
jq
可能有一种方法可以使用 JSON1 直接在 SQLite 中执行此操作,但鉴于我已经在导入 SQLite 之前已经使用过处理数据,因此我没有追求这一点。
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
您可以使用spyql。spyql 读取 json 文件(每行 1 个 json 对象)并生成可以通过管道传输到 sqlite 的 INSERT 语句:
$ spyql -Otable=my_table "SELECT json->uri, json->user_agent FROM json TO sql" < sample3.json | sqlite3 my.db
这假设您已经在 sqlite 数据库中创建了一个空表my.db
。
免责声明:我是 spyql 的作者。