在表复制操作中更新现有行和INSERT不存在行的最有效方法是什么?

时间:2012-05-24 08:17:47

标签: mysql sql

我有两张桌子:

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 job运行上面的SQL。因此,在下一次执行时,SQL应该更新现有产品并插入不存在的产品。

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

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

5 个答案:

答案 0 :(得分:1)

使用DUPLICATE KEY UPDATE

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

答案 1 :(得分:1)

这是更新:

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

应该没问题,试一试。

答案 2 :(得分:0)

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

在块中的SP中捕获DUPLICATE KEY例外和UPDATE。如果没有抛出EXCEPTION,它将INSERT

答案 3 :(得分:0)

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 ...])

答案 4 :(得分:0)

经过一些谷歌搜索并在这里试验答案后,我想出了这个解决方案。事实证明,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)
);

文档: