您的主题是参照完整性。在MySQL中,您可以通过数据库触发器强制执行此类完整性。
例如,您可以定义执行delete
发生在一个父记录之前触发:
CREATE TRIGGER trg_books_bef_delete
BEFORE DELETE
ON books
FOR EACH ROW
BEGIN
DELETE FROM book_groups WHERE book_id = old.book_id;
END;
这个特殊的触发器将在book_groups
是指被删除book
记录删除任何相关记录。
您可以决定采取不同的响应方式,并且在具有相关记录的book
记录被删除时引发错误。由于从MySQL 5.5,你可以这样做:
CREATE TRIGGER trg_books_bef_delete
BEFORE DELETE
ON books
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*) FROM book_groups WHERE book_id = old.book_id) > 0
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Foreign Key Constraint Violated!';
END IF;
END;
在这种情况下,如果book_groups
记录被发现,是指book
记录被删除,狠狠地抛出异常,而delete
操作被取消。
您可以通过MySql
here了解参考完整性。
您可以在PHP
中做类似的事情,但在通过其他工具(如phpAdmin
)连接时,可能会绕过此类代码。触发器的优势在于它们独立于连接的位置执行,并且它们在与原理操作相同的事务中执行。缺点是你有另一层代码来维护,旁边的php
代码。而且php
代码必须知道这些触发器可能具有的其他表的副作用。
的一些想法做一个在php
book
受控delete
:
$confirmed = false;
if (isset($_POST["confirm"])) {
$confirmed = true;
}
$book_id = $_POST["book_id"]);
$con = mysqli_connect(...);
// Check for dependent records that would also be deleted:
if ($stmt = mysqli_prepare($con,
"SELECT COUNT(*) AS cnt FROM book_groups WHERE book_id = ?")) {
mysqli_stmt_bind_param($stmt, "i", $book_id);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $cnt);
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
if ($cnt > 0 && !$confirmed) {
?>
<html>
<body>
<form action="" method="post">
<input type="hidden" name="book_id" value="<?=$book_id?>"/>
This book is categorised in groups,
are you sure to delete that information?
<input type="submit" value="confirm" name="confirm"/>
</form>
</body>
</html>
<?php
exit;
}
}
// continue to delete book below...
你正确地联系起来。一种解决方案是在代码中有一个规定,如果一本书被删除,那么依赖该书的book_groups也会被删除。许多MVC框架都具有开箱即用的解决方案,例如Rails依赖的::destroy(我知道你在使用PHP--这只是想到的第一个例子) – jackel414
对我来说似乎是一对多映射。我猜想INNER JOIN查询的时间太晚了?我认为“book_group”应该只是与书相关联的id列表,然后通过group_id进行INNER JOIN,您只能获取存储在books表中的书籍,稍后可以修剪book_group。 – DataHerder
我不想删除任何组。我只想要能够改变哪本书目前与之相关联。我对MVC框架一无所知(这对我来说都是新的),但我会研究它。 – Bobby