我正在尝试在Python中使用executemany
来填充某些行。
但是,我得到了:
sqlite3.OperationalError: 3 values for 4 columns
我理解一般情况下,您使用executemany
尽可能高效地将原始值填充到数据库中,考虑到这一点,您通常希望插入的值的数量与列数相匹配。 / p>
但是如果一个或多个列是通过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”中) “case”,因为SELECT
在这种情况下不返回任何行。
答案 0 :(得分:4)
你的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
如果你需要默认值,如果select没有返回任何内容,你可以使用它:
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)))
答案 1 :(得分:0)
是的!有一个更好的方法!将VALUES
子句替换为SELECT
语句!
查询将如下所示:
INSERT OR REPLACE INTO test (id, a, b, c)
SELECT ?, a, b, ? FROM test WHERE id = ?
请记住更改data
列表,因为现在参数的顺序不同。