我想将数据库中包含的所有表读入pandas数据帧。 This回答了我想要完成的任务,但我想使用?
而不是%s
的{{3}}的DBAPI语法。但是,我遇到了一个错误。我认为documentation可以解决这个问题,但我现在发布自己的问题,因为我无法弄明白。
最小例子
import pandas as pd
import sqlite3
pd.__version__ # 0.19.1
sqlite3.version # 2.6.0
excon = sqlite3.connect('example.db')
c = excon.cursor()
c.execute('''CREATE TABLE stocks
(date text, trans text, symbol text, qty real, price real)''')
c.execute("INSERT INTO stocks VALUES ('2006-01-05', 'BUY', 'RHAT', 100, 35.14)")
c.execute('''CREATE TABLE bonds
(date text, trans text, symbol text, qty real, price real)''')
c.execute("INSERT INTO bonds VALUES ('2015-01-01', 'BUY', 'RSOCK', 90, 23.11)")
data = pd.read_sql_query('SELECT * FROM stocks', excon)
# >>> data
# date trans symbol qty price
# 0 2006-01-05 BUY RHAT 100.0 35.14
但是当我在下面添加?
或(?)
时,收到错误消息pandas.io.sql.DatabaseError: Execution failed on sql 'SELECT * FROM (?)': near "?": syntax error
。
问题代码
c.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = c.fetchall()
# >>> tables
# [('stocks',), ('bonds',)]
table = tables[0]
data = pd.read_sql_query("SELECT * FROM ?", excon, params=table)
我可能缺少一些微不足道的东西,但我没有看到它!
答案 0 :(得分:1)
问题在于您尝试对表名使用参数替换,这是不可能的。有一个issue on GitHub可以讨论这个问题。相关部分位于主题的最后,在@jorisvandenbossche的评论中:
表名AFAIK无法进行参数替换。
问题是,在sql中,字符串之间经常存在差异 引用和变量引用(参见例如 https://sqlite.org/lang_keywords.html报价的区别 字符串和标识符之间)。所以你要填写一个字符串 是为了sql其他东西作为变量名称(在这种情况下是一个表 名称)。
答案 1 :(得分:0)
在这个特定示例中,您直接从数据库自己的元数据中获取表名,这已经是安全的,因此可以仅使用普通字符串格式来构造查询,但将表名括在引号中仍然很好。< /p>
如果您要获取用户输入的表名,您也可以先参数化它们,然后再将它们用于普通的 Python 字符串格式。
例如
# assume this is user-entered:
table = '; select * from members; DROP members --'
c.execute("SELECT name FROM sqlite_master WHERE type='table' and name = ?;", excon, params=table )
tables = c.fetchall()
在这种情况下,用户输入了一些旨在造成破坏的恶意输入,参数化查询将清除它,查询将不返回任何行。
如果用户输入了一个干净的表格,例如table = 'stocks'
那么上面的查询将通过清洗将相同的名称返回给您,现在它是安全的。
然后可以继续正常的python字符串格式化,在这种情况下使用f-string样式:
table = tables[0]
data = pd.read_sql_query(f"""SELECT * FROM "{table}" ;""", excon)
回到你原来的例子,我上面的第一步是完全没有必要的。我只是提供了它的上下文。这是不必要的,因为没有用户输入,所以你可以做这样的事情来获取每个表的数据框字典。
c.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = c.fetchall()
# >>> tables
# [('stocks',), ('bonds',)]
dfs = dict()
for t in tables:
dfs[t] = pd.read_sql_query(f"""SELECT * FROM "{t}" ;""", excon)
然后您可以使用表名作为键从字典中获取数据框。