Mysql 更新行,如果更新失败,则删除同一行

Mysql 更新行,如果更新失败,则删除同一行,mysql,sql,Mysql,Sql,我有一个汇总项目及其类别的表。一个项目可以有多个类别。以下是简化的模式和示例数据: 表名称:定义为主键的外部参照(itemID,catID) itemID | catID -------+------- 4059 | 159 4059 | 219 我还有一个类别合并功能。执行此操作时,我还将在源类别中链接的产品移动到目标(合并)类别。为了将项目从类别159移动到类别219,我使用如下SQL: UPDATE `xref` SET `catID` = 219 WHERE `catID` =

我有一个汇总项目及其类别的表。一个项目可以有多个类别。以下是简化的模式和示例数据:

表名称:定义为主键的外部参照(itemID,catID)

itemID | catID
-------+-------
4059   | 159
4059   | 219
我还有一个类别合并功能。执行此操作时,我还将在源类别中链接的产品移动到目标(合并)类别。为了将项目从类别159移动到类别219,我使用如下SQL:

UPDATE `xref` SET `catID` = 219 WHERE `catID` = 159
但是更新失败,因为已经存在4059-219(PK约束)

期望的结果是

itemID | catID
-------+-------
4059   | 219
我不能在数据库上使用存储过程或函数,但可以在应用程序中实现所需的步骤

  • 当更新查询失败时,是否有方法删除行
  • 如何编写一个“预测”将要失败的更新查询的行的查询?类似于“returnitemid是指同时拥有catID的219和159”。
    SELECT*FROM xref,其中(159219)GROUP BY itemID中的catID具有COUNT(*)>=2
    是正确的方法吗
尝试以下查询:

UPDATE `xref` 
SET `catID` = 219 
WHERE `catID` = 159
and `itemID` not in (select 'itemID' 
                     from (select *from 'xref') x
                     where 'catID' = 219)
;

希望有帮助

这种方式暂时删除您的约束以允许更新,然后将它们放回末尾

如果您的数据库是生产数据库,请对副本进行测试

# set up tables for the purpose of this example
CREATE TABLE Item
(
    ItemId INT,
    ItemName VARCHAR(255),
    PRIMARY KEY (ItemId)
);

 CREATE Table Category
 (
     CatId INT,
     CatName VARCHAR(255),
      PRIMARY KEY (CatId)
 );

 CREATE TABLE xref
(
    ItemId INT,
    CatId INT,
    PRIMARY KEY (ItemId,CatId),
    FOREIGN KEY (ItemID) REFERENCES Item(ItemId),
    FOREIGN KEY (CatId) REFERENCES Category(CatId)
 );

 # insert data for the purpose of this example
 INSERT INTO Item
 VALUES
 (1,'Hammer'),
 (2,'Chisel'),
 (3,'Wrench');

 INSERT INTO Category
 VALUES
 (159,'Tool'),
 (219,'Toy'),
 (3,'foo');

 INSERT INTO xref
 VALUES
 (1,159),
 (1,219),
 (2,159),
 (3,3);

 START TRANSACTION;

# remove constraints so we can run the update
ALTER TABLE xref DROP FOREIGN KEY xref_ibfk_1;
ALTER TABLE xref DROP FOREIGN KEY xref_ibfk_2;
ALTER TABLE xref DROP PRIMARY KEY;

# Update the categories
UPDATE xref SET CatId = 219 WHERE CatId = 159;

# Copy the table into a tmep table but exclude duplicates we have created above
CREATE TEMPORARY TABLE IF NOT EXISTS xref_tmp AS (SELECT DISTINCT
                                                           ItemId,
                                                           CatId
                                                    FROM    xref);

# Empty the original table
DELETE FROM xref;

# Copy the clean results back to the orginal table
INSERT INTO xref
SELECT * FROM xref_tmp;

# put our constaints back
ALTER TABLE xref ADD PRIMARY KEY (ItemId,CatId);
ALTER TABLE xref ADD FOREIGN KEY (ItemID) REFERENCES Item(ItemID);
ALTER TABLE xref ADD FOREIGN KEY (CatID) REFERENCES Category(CatID);

COMMIT

我不能使用@JNevill的方法,因为我不知道事先会受到itemID的影响。但这给了我一个两步解决方案的想法

UPDATE IGNORE `xref` SET `catID` = 219 WHERE `catID` = 159
DELETE FROM `xref` WHERE `catID` = 159

感谢您提供的所有其他答案/评论。

您不能将“更新”调用放入try块中,如果失败(引发异常),请运行删除代码吗?当然,您需要确保您正在侦听要抛出的正确异常。您可以分两个步骤来完成此操作。步骤1:删除
itemid
的任何记录,其中
catid
等于要将其更新到的内容。2) 运行更新。这似乎是倒退,对吗?但它肯定会成功的。谢谢。这将防止PK约束错误,但仍将幻影记录(4059 | 159)保留在数据库中。之后我仍然需要删除它。更新忽略也做同样的事情,但更短,所以我在回答中选择了它。你可以在更新之后删除它。但是是的,
updateignore
将是一种更好的方法。