【问题标题】:What is the most efficient way to UPDATE existing rows and INSERT non-exist rows in a table-copy operation?在表复制操作中更新现有行和插入不存在行的最有效方法是什么?
【发布时间】:2012-05-24 08:17:47
【问题描述】:

我有 2 张桌子:

stock:

pid name qty
--- ---- ---
1   aaaa   2
2   bbbb   3
1   aaaa   5
3   cccc   1
2   bbbb   2

stock_total:

pid name total_qty
--- ---- ---------

我可以使用此查询从stock 表中将总数量的行插入stock_total

INSERT INTO stock_total (pid, name, total_qty)
SELECT pid, name, SUM(qty) 
FROM stock
GROUP BY pid, name

问题是,我将通过 cron 作业运行上面的 SQL。所以在下一次执行时,SQL 应该更新现有产品并插入不存在的产品。

如果我遍历 SELECT 结果,检查每一行是否存在于stock_total 并执行 INSERT 或 UPDATE,效率会非常低。

有没有更简单的方法来实现这一点?也许通过修改上面的 SQL。谢谢。

【问题讨论】:

标签: mysql sql


【解决方案1】:

使用DUPLICATE KEY UPDATE:

INSERT INTO TABLENAME(col1, col2)
VALUES (@value, ‘yyy’)
ON DUPLICATE KEY UPDATE col1 = @value

【讨论】:

    【解决方案2】:

    这是为了更新:

    UPDATE stock_total
    SET total_qty = SUM(s.qty)
    FROM stock_total st
    INNER JOIN stock s
    ON st.pid = s.pid
    AND st.name = s.name
    WHERE s.pid = st.pid
    GROUP BY s.pid
    

    这是插入:

    INSERT INTO stock_total
    SELECT s.pid, s.name, SUM(s.qty)
    FROM stock s
    WHERE s.pid NOT IN (SELECT pid FROM stock_total)
    GROUP BY s.pid, s.name
    

    应该没问题,试试看。

    【讨论】:

    • 感谢 Majid,我不熟悉我使用 SQL Server 的这种语法,如果可以改进查询或答案,请随时根据您的建议编辑我的帖子。
    • UPDATE 不起作用,INSERT 错过了GROUP BY。但我明白你的意思。谢谢。
    • 谢谢,我修好了插页。您在更新时遇到什么错误?
    【解决方案3】:

    为什么不从作业中调用存储过程?

    在块中的 SP 中捕获 DUPLICATE KEY 异常和 UPDATE。如果没有EXCEPTION 被抛出,它会INSERT

    【讨论】:

    • 我不是SP粉丝,但很好的回答。
    【解决方案4】:

    merge 是您要搜索的内容。如下使用 -

    merge into stock_total s " +
                            "using (select ? pid, ? name, ? total_qty from dual) d " +
                            "on (s.pid = d.pid and s.name = d.name and s.total_qty = d.total_qty) " +
                            "when matched then " +
                            "update set s.pid= d.pid, s.name = d.name, s.total_qty = d.total_qty" +
                            "when not matched then " +
                            "insert (pid, name, total_qty) " + 
                            "values(d.pid, d.name, d.total_qty)" ;
    

    编辑(对于 mySQL):

    MERGE INTO table_name WITH (HOLDLOCK) USING table_name ON (condition)
    WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...]
    WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...])
    

    【讨论】:

    • 我根据OP的原始问题回答了它,然后将其添加到mysql标签中。但这对甲骨文非常有效。对于 mysql,请参阅我的编辑...
    • 我认为最后的 SQL 会很长,WITH (HOLDLOCK) 把我吓坏了 :)。不过谢谢。
    【解决方案5】:

    经过一番谷歌搜索并尝试了这里的答案,我想出了这个解决方案。原来MySQL支持REPLACE INTO......ON DUPLICATE KEY UPDATE。所以我的查询是这样的:

    REPLACE INTO stock_total
    SELECT pid, name, SUM(qty)
    FROM stock
    GROUP by pid, name
    

    或者,

    INSERT INTO stock_total
    SELECT pid, name, SUM(qty)
    FROM stock
    GROUP by pid, name
    ON DUPLICATE KEY UPDATE total_qty=VALUES(total_qty)
    

    如果stock_total 上存在一行,第一个查询将删除然后插入新行, 第二个查询将更新现有行。

    只有当表有主键或唯一索引时,这两个查询才会起作用:

    CREATE TABLE stock_total (
        pid         INT         NOT NULL,
        name        VARCHAR(20) NOT NULL,
        total_qty   INT         NOT NULL,
    
        UNIQUE (pid, name)
    );
    

    文档:

    【讨论】:

      猜你喜欢
      • 2012-04-10
      • 2010-09-22
      • 2011-12-06
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      相关资源
      最近更新 更多