简体   繁体   中英

mysql: update a table's primary key which is referred by another table as foreign key

This is my DB structure

CREATE DATABASE Library;

CREATE TABLE Library.Book (
    ID        char(8),
    name      varchar(10) NOT NULL,
    author    varchar(10),
    price     float,
    status     int DEFAULT 0,
    PRIMARY KEY (ID),
    CHECK ( status >= 0 and status <= 1 ),
    CHECK ( price >= 0 )
);

CREATE TABLE Library.Reader (
    ID        char(8),
    name      varchar(10),
    age       int,
    address   varchar(20),
    PRIMARY KEY (ID)
);

CREATE TABLE Library.Borrow (
    Book_ID      char(8),
    Reader_ID    char(8),
    Borrow_Date  date,
    Return_Date  date,
    CONSTRAINT FK_Book_ID FOREIGN KEY (Book_ID) REFERENCES Library.Book(ID),
    CONSTRAINT FK_Reader_ID FOREIGN KEY (Reader_ID) REFERENCES Library.Reader(ID)
);

and I write a store procedure as below

DELIMITER //
CREATE PROCEDURE Library.ChangeBookID (IN OriginID char(8), IN ModifiedID char(8))
BEGIN
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION #处理异常
        SET @STATUS = 1;
    CREATE TABLE Library.book_copy
    SELECT ID
    FROM Library.Book;
    START TRANSACTION;
    UPDATE Library.book_copy
        SET Library.book_copy.ID = ModifiedID
        WHERE Library.book_copy.ID = OriginID;
    if @STATUS = 0 THEN   #status = 0 means no transaction
        ALTER TABLE Library.Borrow
        DROP FOREIGN KEY FK_Book_ID;

        UPDATE Library.Borrow
            SET Library.Borrow.Book_ID = ModifiedID
            WHERE Library.Borrow.Book_ID = OriginID;

        DROP TABLE Library.Book;
        RENAME TABLE Library.Book_copy TO Library.Book;

        ALTER TABLE Library.Borrow
        ADD CONSTRAINT FK_Book_ID FOREIGN KEY (Book_ID) REFERENCES Library.Book(ID);
        COMMIT;
    ELSE
        ROLLBACK ;
    END IF;
END //
DELIMITER ;

What I want is that if the modified primary key value is conflicted with the rest of this table, the procedure will rollback, else it will commit the changes. However, it doesn't work as I expected.

I still do not know why the store procedure I wrote before goes wrong, but with Barmar's help, I get another way which is much cleaner to solve this question. Now, the new store procedure is as below:

DELIMITER //
CREATE PROCEDURE Library.ChangeBookID (IN OriginID char(8), IN ModifiedID char(8))
BEGIN
    START TRANSACTION;
    IF NOT EXISTS(SELECT 1 FROM Library.book WHERE ID = ModifiedID) THEN
        ALTER TABLE Library.Borrow
        DROP FOREIGN KEY FK_Book_ID;

        UPDATE Library.Book
            SET Library.Book.ID = ModifiedID
        WHERE Library.Book.ID = OriginID;

        UPDATE Library.Borrow
            SET Library.Borrow.Book_ID = ModifiedID
        WHERE Library.Borrow.Book_ID = OriginID;

        ALTER TABLE Library.Borrow
        ADD CONSTRAINT FK_Book_ID FOREIGN KEY (Book_ID) REFERENCES Library.Book(ID);

        COMMIT;
    ELSE
        ROLLBACK;
    END IF;
END //
DELIMITER ;

Thank Barmar again and also thx4 tadman's help.

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