首页 > 解决方案 > fetchmany(1) 在 UPDATE 后中断

问题描述

我正在编写一个 python + sqlite3 数据库管理功能,系统中的每一次“销售”都必须在产品数量足够多的情况下完成,并且每次“供应”都可以随时完成。

我正在尝试进行数据库查询并获取一行,然后更新它的一个条目并使用同一个表来获取下一行。对于下一行查询,所有更新都应该可见。出于某种原因(我不明白并且很乐意) acursor.Execute(#some update#)会破坏前一个cursor.fetchmany(1),这将在退出 while 循环时结束。

这是代码:

def act():
    selection = """SELECT Products_tab.quantity as old_quantity, 
                    Activities_tab.quantity as new_quantity, 
                    Products_tab.id
                    FROM Products_tab inner join Activities_tab on 
                    Products_tab.id=Activities_tab.product_id"""
    cursor.execute(selection)

    while True:
        row_list = cursor.fetchmany(1)
        if row_list:
            quantity = row_list[0][0]
            change_amount = row_list[0][1]
            new_quantity = quantity + change_amount
            product_id = row_list[0][2]
            if change_amount < 0:  # sell
                if new_quantity >= 0:           # just to check if sell is possible
                    cursor.execute("""UPDATE Products_tab SET quantity=({})
                                WHERE id = ({})""".format(new_quantity, product_id))
        else:
            break

我想了解它为什么会发生(因为我在网上找不到任何信息),以及如何解决它。谢谢 :)

标签: sqlpython-3.xdatabasesqlite

解决方案


可能,问题涉及您对游标的处理。考虑将它们分解并确保使用参数化:

# USE TWO CURSORS
sel_cursor = conn.cursor()     
upd_cursor = conn.cursor()

selection = ...

while True: 
   sel_cursor.execute(selection)         # MOVE INSIDE LOOP
   row_list = cursor.fetchmany(1) 

   if row_list: 
       ...
       # ACTION QUERY WITH PARAMS
       upd_cursor.execute("""UPDATE Products_tab 
                             SET quantity = ? WHERE id = ?""", 
                          [new_quantity, product_id])
       conn.commit()
   else:
       break

但是,请避免使用循环和 Python 参数,并以其基于集合的效率运行一个纯 SQL。由于 SQLite 不支持UPATE...JOINor UPDATE...FROM,因此多次使用子查询,包括CASE关联两个表中的产品数量的逻辑。

UPDATE Products_tab p
SET p.quantity = CASE
                    WHEN (SELECT quantity
                          FROM Activities_tab
                          WHERE product_id = p.id) < 0
                          AND
                         (p.quantity + (SELECT quantity
                                        FROM Activities_tab
                                        WHERE product_id = p.id)) >= 0
                    THEN (p.quantity + (SELECT quantity
                                        FROM Activities_tab
                                        WHERE product_id = p.id)) 
                    ELSE p.quantity
                 END
WHERE p.ID IN
   (SELECT product_id 
    FROM Activities_tab)

推荐阅读