简体   繁体   中英

Update row, delete the same row if update fails

I have a table that aggregate items and their categories. An item can have multiple categories. Here is the simplified schema and example data:

Table name: xref, (itemID, catID) defined as primary key

itemID | catID
-------+-------
4059   | 159
4059   | 219

I also have a category merge function. When doing this, I also move products that linked in source category to the destination (merged) category . For moving items from category 159 to 219, I use a SQL like this:

UPDATE `xref` SET `catID` = 219 WHERE `catID` = 159

But the update fails because there is already a 4059-219 (PK constraint).

The desired result is

itemID | catID
-------+-------
4059   | 219

I can't use stored procedures or functions on the database but can implement the required steps in my application.

  • Is there a way to delete row when an UPDATE query fails?
  • How can I write a query that "predicts" rows for to-be-failed UPDATE query? Something like "return itemID's that having catID's 219 AND 159 at the same time". Is SELECT * FROM xref WHERE catID IN (159, 219) GROUP BY itemID HAVING COUNT(*) >= 2 is a correct approach?

I can't use @JNevill's approach because I don't know to-be-affected itemID's beforehand. But that give me an idea for this 2 step solution.

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

Thanks for the all other answers/comments.

Try following query:

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

Hope it helps!

This way temporarily removes your constraints to allow the update and then puts them back at the end.

If your database is a production database TEST ON A COPY!

# 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM