带有元组的Python SQLite3 UPDATE仅使用最后一个值

时间:2015-09-19 16:05:20

标签: python sqlite

我正在尝试使用大元组更新数据库的1列的所有行。

c.execute("SELECT framenum FROM learnAlg")
db_framenum = c.fetchall()
print(db_framenum)

db_framenum_new = []
# How much v6 framenum differentiates from v4
change_fn = 0
for f in db_framenum:
    t = f[0]
    if t in change_numbers:
        change_fn += 1
    t = t + change_fn
    db_framenum_new.append((t,))

print("")
print(db_framenum_new)
c.executemany("UPDATE learnAlg SET framenum=?", (db_framenum_new))

首先,我采用“framenum”列的现有值,如下所示:

[(0,), (1,), (2,) , ..., (104,)]

然后我将元组转换为列表,这样我就可以在for f in db_framenum:循环中更改一些值,从而产生类似的元组:

[(0,), (1,), (2,) , ..., (108,)]

问题

到目前为止一直很好,但后来我尝试使用这些新的framenumber更新列'framenum':

c.executemany("UPDATE learnAlg SET framenum=?", (db_framenum_new))

我希望列'framenum'中的行具有新值,但它们都具有值: 108 (这是元组'db_framenum_new'的最后一个值)。为什么他们没有按顺序更新(从1到108)?

期望值:

framenum: 1, 2, .., 108

GOT:

framenum: 108, 108, ..., 108
  • 注意:元组列表没有变长,只有某些值已更改为。高于46的所有内容都有+1,高于54的所有内容+1(总共+2)...
  • 注2:使用以下命令创建列:'framenum INTEGER'。如果这很重要,另一列有PRIMARY KEY,用'framekanji TEXT PRIMARY KEY'制作,它具有(现在)所有值'NULL'。

修改

解决了我的问题,但我仍然对正确使用c.executemany()感兴趣。我不知道为什么这只会更新第一个rowid:

c.execute("SELECT rowid, framenum FROM learnAlg")
db_framenum = c.fetchall()
print(db_framenum)

db_framenum_new = []
# How much v6 framenum differentiates from v4
change_fn = 0
for e, f in enumerate(db_framenum):
    e += 1
    t = f[1]
    if t in change_numbers:
        change_fn += 1
        t = t + change_fn
        db_framenum_new.append((e,t))

    print(db_framenum_new)
    c.executemany("UPDATE learnAlg SET framenum=? WHERE rowid=?",
                   (db_framenum_new[1], db_framenum_new[0]))

1 个答案:

答案 0 :(得分:2)

是的,您告诉数据库使用相同的framenum更新所有行。那是因为UPDATE语句没有选择任何特定的行。您需要告诉数据库一次更改一行,方法是为每个值包含一个主键。

由于您只是在改变特定的框架编号,因此您可以要求数据库仅提供这些特定的行而不是通过所有这些行。您可能还需要指定一个订单来更改数字;也许你需要在增加framenumber顺序时这样做?

c.execute("""
    SELECT rowid, framenum FROM learnAlg
    WHERE framenum in ({})
    ORDER BY framenum
    """.format(', '.join(['?'] * len(change_numbers))), 
    change_numbers)
update_cursor = conn.cursor()    
for change, (rowid, f) in enumerate(c, 1):
    update_cursor.execute("""
        UPDATE learnAlg SET framenum=? WHERE rowid=?""",
        (f + change, rowid))

我在那里稍微改变了结构;查询仅通过change_numbers子句将结果限制为WHERE IN序列中的帧编号。我直接循环游标(不需要一次获取所有结果)并使用单独的UPDATE来设置新的帧编号。我使用enumerate()代替手动计数器来为我计算。

如果您需要按change_numbers 分组更新,那么只需告诉数据库执行这些更新:

change = len(change_numbers)
for framenumber in reversed(change_numbers):
    update_cursor.execute("""
        UPDATE learnAlg SET framenum=framenum + ? WHERE framenum=?
        """, (change, framenumber))
    change -= 1

这从最高框架编号开始,以避免更新之前已更新的框架编号。这假设您的change_numbers按递增顺序排序。

您的executemany更新应该只传入整个列表,而不仅仅是前两个项目;你需要改变你追加价值的方式:

for e, f in enumerate(db_framenum):
# ...
    db_framenum_new.append((t, e))  # framenum first, then rowid


c.executemany("UPDATE learnAlg SET framenum=? WHERE rowid=?",
               db_framenum_new)

请注意,executemany()调用是在外部 for循环进行的!