在 Python 中将 JSON 转换为 SQLite - 如何将 json 键正确映射到数据库列?

问题描述 投票:0回答:2

我想将我创建的 JSON 文件转换为 SQLite 数据库。

我的目的是稍后决定哪种数据容器和入口点最好,json(通过文本编辑器输入数据)还是 SQLite(通过类似于 SQLiteStudio 的电子表格 GUI 进行数据输入)。

我的json文件是这样的(包含我所在城市的一些十字路口的交通数据):

...
"2011-12-17 16:00": {
    "local": "Av. Protásio Alves; esquina Ramiro Barcelos",
    "coord": "-30.036916,-51.208093",
    "sentido": "bairro-centro",
    "veiculos": "automotores",
    "modalidade": "semaforo 50-15",
    "regime": "típico",
    "pistas": "2+c",
    "medicoes": [
        [32, 50],
        [40, 50],
        [29, 50],
        [32, 50],
        [35, 50]
        ]
    },
"2011-12-19 08:38": {
    "local": "R. Fernandes Vieira; esquina Protásio Alves",
    "coord": "-30.035535,-51.211079",
    "sentido": "único",
    "veiculos": "automotores",
    "modalidade": "semáforo 30-70",
    "regime": "típico",
    "pistas": "3",
    "medicoes": [
        [23, 30],
        [32, 30],
        [33, 30],
        [32, 30]
        ]
    }
...

我已经创建了一个很好的数据库,与这些 Python 代码行具有一对多关系:

import sqlite3

db = sqlite3.connect("fluxos.sqlite")
c = db.cursor()

c.execute('''create table medicoes
         (timestamp text primary key,
          local text,
          coord text,
          sentido text,
          veiculos text,
          modalidade text,
          pistas text)''')

c.execute('''create table valores
         (id integer primary key,
          quantidade integer,
          tempo integer,
          foreign key (id) references medicoes(timestamp))''')

但问题是,当我准备使用类似

c.execute("insert into medicoes values(?,?,?,?,?,?,?)" % keys)
的内容插入包含实际数据的行时,我意识到,由于从 JSON 文件加载的字典没有特殊顺序,因此它无法正确映射到列顺序数据库的。

所以,我问:“我应该使用哪种策略/方法以编程方式从 JSON 文件中的每个“块”读取密钥(在本例中为“local”、“coord”、“sentido”、“veiculos”、“ modalidade”、“regime”、“pistas” e “medicoes”),使用相同顺序的列创建数据库,然后插入具有正确值的行”?

我对 Python 有一定的经验,但我才刚刚开始接触 SQL,所以我想获得一些关于良好实践的咨询,但不一定是现成的秘诀。

python json sqlite database-design
2个回答
55
投票

你有这个Python代码:

c.execute("insert into medicoes values(?,?,?,?,?,?,?)" % keys)

我认为应该是

c.execute("insert into medicoes values (?,?,?,?,?,?,?)", keys)

因为

%
运算符 希望其左侧的字符串包含格式化代码。

现在,完成这项工作所需要做的就是让

keys
成为一个元组(或列表),其中包含正确顺序的 medicoes 表新行的值。考虑以下 python 代码:

import json

traffic = json.load(open('xxx.json'))

columns = ['local', 'coord', 'sentido', 'veiculos', 'modalidade', 'pistas']
for timestamp, data in traffic.iteritems():
    keys = (timestamp,) + tuple(data[c] for c in columns)
    print str(keys)

当我使用您的示例数据运行此程序时,我得到:

(u'2011-12-19 08:38', u'R. Fernandes Vieira; esquina Prot\xe1sio Alves', u'-30.035535,-51.211079', u'\xfanico', u'automotores', u'sem\xe1foro 30-70', u'3')
(u'2011-12-17 16:00', u'Av. Prot\xe1sio Alves; esquina Ramiro Barcelos', u'-30.036916,-51.208093', u'bairro-centro', u'automotores', u'semaforo 50-15', u'2+c')

这似乎是您需要的元组。

您可以添加必要的 sqlite 代码,如下所示:

import json
import sqlite3

traffic = json.load(open('xxx.json'))
db = sqlite3.connect("fluxos.sqlite")

query = "insert into medicoes values (?,?,?,?,?,?,?)"
columns = ['local', 'coord', 'sentido', 'veiculos', 'modalidade', 'pistas']
for timestamp, data in traffic.iteritems():
    keys = (timestamp,) + tuple(data[c] for c in columns)
    c = db.cursor()
    c.execute(query, keys)
    c.close()

编辑:如果您不想对列列表进行硬编码,您可以执行以下操作:

import json

traffic = json.load(open('xxx.json'))

someitem = traffic.itervalues().next()
columns = list(someitem.keys())
print columns

当我运行它时,它会打印:

[u'medicoes', u'veiculos', u'coord', u'modalidade', u'sentido', u'local', u'pistas', u'regime']

你可以将它与这样的东西一起使用:

import json
import sqlite3

db = sqlite3.connect('fluxos.sqlite')
traffic = json.load(open('xxx.json'))

someitem = traffic.itervalues().next()
columns = list(someitem.keys())
columns.remove('medicoes')
columns.remove('regime')

query = "insert into medicoes (timestamp,{0}) values (?{1})"
query = query.format(",".join(columns), ",?" * len(columns))
print query

for timestamp, data in traffic.iteritems():
    keys = (timestamp,) + tuple(data[c] for c in columns)
    c = db.cursor()
    c.execute(query)
    c.close()

当我使用您的示例数据尝试时,此代码打印的查询如下所示:

insert into medicoes (timestamp,veiculos,coord,modalidade,sentido,local,pistas) values (?,?,?,?,?,?,?)

0
投票

使用流行的数据操作库

pandas
,将 json 转换为 sqlite 表非常容易,因为很多处理都是由 pandas 完成的。基本上,json 文件可以使用
pandas.read_json
转换为 pandas DataFrame,然后我们可以简单地过滤所需的列并使用
to_sql
转储到 SQLite 表中。

import sqlite3
import pandas as pd

con = sqlite3.connect('data/fluxos.sqlite')
(
    pd.read_json('data/my_json.json', orient='index')
    .filter(['local', 'coord', 'sentido', 'veiculos', 'modalidade', 'pistas'])
    .to_sql('medicoes', con, index_label='timestamp', dtype={'timestamp': 'TEXT PRIMARY KEY'}, if_exists='append')
)
con.close()

但是,如果您不想坚持使用内置库,那么您可以预先处理数据并使用

executemany
让sqlite3 处理循环:

import json
import sqlite3


with open('data/my_json.json') as f:
    my_json = json.load(f)

columns = ['local', 'coord', 'sentido', 'veiculos', 'modalidade', 'pistas']
processed_data = [(timestamp, *(data[c] for c in columns)) for timestamp, data in my_json.items()]

con = sqlite3.connect('data/fluxos.sqlite')
cur = con.cursor()

cur.execute('''
CREATE TABLE medicoes (
    timestamp TEXT PRIMARY KEY,
    local TEXT,
    coord TEXT,
    sentido TEXT,
    veiculos TEXT,
    modalidade TEXT,
    pistas TEXT)
''')

cur.executemany("INSERT INTO medicoes VALUES (?, ?, ?, ?, ?, ?, ?)", processed_data)
con.commit()
cur.close()
con.close()
© www.soinside.com 2019 - 2024. All rights reserved.