更新/插入/删除数据库中的子记录

时间:2013-01-17 17:22:33

标签: sqlite one-to-many updates

考虑在两个表中保存在数据库中的经典销售订单:

SALE_ORDER                   SALE_ORDER_ITEM
----------                   ---------------
id       integer             ...
...                           order_id        integer references sale_order (id)
                              item_id         integer references item (id)
                              quantity        integer
                              ...

出于这个问题的目的,忽略对另一个表的item_id引用 - 它是无关紧要的。

我有一个包含订单的类,例如:

public class SaleOrder {
    private int orderId;
    ...
    private List<BoughtItem> items;
    ....
}

订单可以更改(我的要求),更改可以包括列表中的项目:添加,删除或更改数量的项目。当我在数据库中更新此订单时,显而易见的最简单的事情是delete from sale_order_item where order_id=<my_order_id>然后插入列表中的行。然而,这似乎对我来说效率很低,特别是考虑到列表可以包含(可能)数百个不同的项目。 (背景:这些是从超市到批发产品供应商的订单。)

另一种方法是查询数据库,然后将列表与光标进行比较,在必要时添加,删除或更新 - 这似乎至少效率低下。

  1. 是否有另一种(第三种?)方法效率更高?
  2. 如果没有,哪两个更好?我总是使用第一个(删除所有,然后重新插入,但现在开始怀疑自己。
  3. 更新:数据库是sqlite3(如果重要的话,在android上)

4 个答案:

答案 0 :(得分:0)

如果您还没有PK,请在sale_order_item上使用PK。

保留可在重新启动数据库时重放的脏缓冲区。因此,如果用户更改了某个项目,请添加条目'update sale_order_item set item_id =“1234”,其中sale_order_item.id =“2222”'。

然后,当涉及与数据库通信时,回放这些更改。记录更改并不重要(记录SQL不是最有效的)。关键是能够识别每个项目中的更改,或添加/删除项目,然后能够基于此创建sql。

我希望它能给你一个想法。

答案 1 :(得分:0)

这实际取决于您是要更新项目还是只是重新插入它们。如果您不需要进行任何更新,如果您将现有项添加到子句中,则删除+插入将没有问题(因此您不会删除新列表中的内容)

如果新列表总是黄金,那么使用游标是没有意义的,因为你已经有了数据,所以只需坚持删除/重新插入 - 它不像光标那样效率低。

e.g。 T-SQL

insert into sale_order_item(columns..)
select field1, 2, etc. from your_new_list a 
where not exists (select 1 from sale_order_item where item_id = a.item_id)

答案 2 :(得分:0)

如果您没有项目ID的原始列表,则必须至少删除列表中不再包含的所有项目:

DELETE FROM sale_order_item
WHERE order_id = ?
  AND item_id NOT IN (id1, id2, ...)

如果你不知道它们是否已经改变,你就无法避免更新记录。

但是,可以避免插入已存在的记录: 如果(order_id,item_id)列上有正确的主键,则可以使用INSERT OR REPLACE command

但是,所有这些仅仅是简单的DELETEINSERT的效率。

答案 3 :(得分:0)

  1. 添加字段recordState:enum {rfNone,rfInserted,rfUpdated,rdDeleted}。
  2. 为所有setter方法添加适当的代码,例如

    public void setData(String value) {
        if (!this.data.equals(value)) {
            this.data = value;
            if (getRecordState() == rfNone)
                setRecordState(rfUpdated);
        }    
    }
    

    如果记录类的任何值发生了变化,此代码将确保您将记录对象标记为已更新,当然这个对象不是新构建的

  3. 从数据库读取的所有记录必须是initialy:recordState = rfNone

  4. 新添加的记录必须标记为:recordState = rfInserted at creation
  5. 必须标记已删除的记录:recordState = rfDeleted(不要立即删除)
  6. 在记录对象的结尾遍历列表中,并根据recordState值进行适当的操作