[英]Python + sqlite3: executemany with “constructed” values
我正在尝试在Python中使用executemany
来填充一些行。
但是,我得到:
sqlite3.OperationalError: 3 values for 4 columns
我知道,通常,您可以使用executemany
将原始值尽可能有效地填充到数据库中,并且牢记这一点,通常希望插入的值数与列数匹配。
但是,如果一个或多个列是通过SQL“构造”的,并且没有任何对应的输入值怎么办?
小例子:
#!/usr/bin/env python2.7
import os
import sys
import sqlite3
from contextlib import closing
DB_FILE = 'test.sqlite'
with closing(sqlite3.connect(DB_FILE)) as db:
# First, some setup...
cursor = db.cursor()
cursor.execute('CREATE TABLE test (id TEXT PRIMARY KEY, a TEXT, b TEXT, c TEXT)')
sql = '''INSERT INTO test (id, a, b, c) VALUES (?, ?, ?, ?)'''
data = []
for i in range(5):
idStr = str(i)
data.append( (idStr, 'a{}'.format(i), 'b{}'.format(i), 'c{}'.format(i)) )
cursor.executemany(sql, data)
# Now, to exercise the problem:
# This does an 'upsert', but the same problem could occur in
# other circumstances.
sql = '''
INSERT OR REPLACE INTO test (id, a, b, c)
VALUES (
?,
(SELECT a,b FROM test WHERE id = ?),
?
)'''
data = []
for i in range(3,7):
idStr = str(i)
data.append( (idStr, idStr, 'c{}'.format(i)) )
cursor.executemany(sql, data)
db.commit()
运行该命令时,您会在顶部看到错误( 3 values for 4 columns
)。
我想可以通过将SELECT a,b
分解为单独的SELECT a..., SELECT b...
部分来解决此问题,但是有更好的方法吗?
给出的示例很小-实际上,可能是10列,我现在必须用自己的(SELECT ...)
子句来详细列出。
更新1这不是我最初想到的特定于executemany
。 即使手工运行普通的SQL也会遇到同样的问题。
更新2下面的答案建议使用SELECT
而不是VALUES
,但是,当添加新行时(如我的“ upsert”情况),此操作不起作用,因为在这种情况下SELECT
返回任何行。
您的SQL需要将4个参数转换为VALUES。 问题是SQLite无法将多个值返回到子查询中,您将遇到以下错误:sqlite3.OperationalError:仅允许单个结果作为表达式的一部分的SELECT
您可以做的是使用2条Select语句,每个要求一个值。 这是我尝试过的:
sql = '''
INSERT OR REPLACE INTO test (id, a, b, c)
VALUES (
?,
(SELECT a FROM test WHERE id = ?),
(SELECT b FROM test WHERE id = ?),
?
)'''
为此,还有一个更优雅的解决方案。
sql = '''
INSERT OR REPLACE INTO test (id, a, b, c)
SELECT
?, a, b, ?
FROM test WHERE id = ?
'''
这是一个工作示例,我进行了一些更改,以便相应地填充数据库表:
#!/usr/bin/env python2.7
import os
import sys
import sqlite3
from contextlib import closing
DB_FILE = 'test.sqlite'
with closing(sqlite3.connect(DB_FILE)) as db:
# First, some setup...
cursor = db.cursor()
cursor.execute('CREATE TABLE test (id TEXT PRIMARY KEY, a TEXT, b TEXT, c TEXT)')
sql = '''INSERT INTO test (id, a, b, c) VALUES (?, ?, ?, ?)'''
data = []
for i in range(5):
idStr = str(i)
data.append( (idStr, 'a{}'.format(i), 'b{}'.format(i), 'c{}'.format(i)) )
cursor.executemany(sql, data)
sql = '''
INSERT OR REPLACE INTO test (id, a, b, c)
SELECT
?, a, b, ?
FROM test WHERE id = ?
'''
data = []
for i in range(4, 7):
data.append((i, 'c{}'.format(i), i - 3))
cursor.executemany(sql, data)
db.commit()
更新1
如果需要默认值以防选择不返回任何内容,则可以使用以下方法:
sql = '''
INSERT OR REPLACE INTO test (id, a, b, c)
VALUES (
?,
(SELECT ifnull((SELECT a FROM test WHERE id = ?), 'Default 1')),
(SELECT ifnull((SELECT b FROM test WHERE id = ?), 'Default 2')),
?
)'''
data = []
for i in range(4, 10):
data.append((i, i, i, 'c{}'.format(i)))
是! 有一个更好的方法! 用SELECT
语句替换VALUES
子句!
查询如下所示:
INSERT OR REPLACE INTO test (id, a, b, c)
SELECT ?, a, b, ? FROM test WHERE id = ?
记住要更改data
列表,因为现在参数的顺序不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.