【问题标题】:Linking rows in the MySQL database and querying with PHP链接 MySQL 数据库中的行并使用 PHP 进行查询
【发布时间】:2015-11-20 05:03:31
【问题描述】:

我刚刚使用 PHP 完成了我的第一个站点,现在我注意到了一个问题。我的很多动态内容都“链接”到其他表中的行。所以当其他表中的那些行被删除时,它显然会给我一个错误。

例如,我有一个表“book_groups”,它从表“books”、“hosts”和“locations”中提取数据。所以在查询了某个 book_group 之后,我会根据 group 中存储的 book_id、host_id 和 location_id 对其他表进行更多查询。

显然我的计划不够好。因为如果一本书不小心被删了又重新添加,id会变,会坏掉。

我的问题是,既然我已经完成了这一切,那么解决这个问题的最佳方法是什么?我可以返回每个查询并添加一个 if( $query_result != false ) 以查看该行是否仍然存在。但是有很多查询,因为我有很多不同类型的组和相关表。

为了将来参考,有没有更好的方法来链接 MySQL 中的表,而不是只存储相关表行的 id?

【问题讨论】:

  • 您正确链接了它们。一种解决方案是在您的代码中提供一个条款,如果一本书被删除,那么依赖该书的 book_groups 也会被删除。许多 MVC 框架为这种功能提供了开箱即用的解决方案,例如依赖于 Rails 的: :destroy (我知道你使用的是 PHP - 这只是我想到的第一个例子)
  • 在我看来是一对多的映射。我想现在 INNER JOIN 您的查询为时已晚?我认为“book_group”应该只是与一本书关联的 id 列表,然后通过 group_id 进行 INNER JOIN,你只会获取存在于 books 表中的书,你可以稍后修剪你的 book_group。
  • 我不想删除任何组。我只想能够更改当前与之关联的书。我对 MVC 框架一无所知(这对我来说是全新的),但我会研究一下。

标签: php mysql hyperlink row


【解决方案1】:

您的主题是参照完整性。在 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 中控制bookdelete 的一些想法:

$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...

【讨论】:

  • 看起来第二种解决方案可能有效。但我希望所有数据库查询都可以通过我用 PHP 创建的 CMS 进行。我能否以某种方式在 PHP 中进行该查询,并在删除之前告诉用户哪些记录仍在依赖它,然后如果需要则提示继续?
  • 当然,你会做一个mysqli_query来计算books_query中具有相同id的记录数,然后看看它是否非零,显示一个用户必须提交他们的页面好的,如果您的 php 看到存在该确认参数,则执行删除。
  • 我为此类php 代码添加了一些指示。未经测试,仅供参考。
  • 看起来这可能就是我需要的。现在我只需要弄清楚所有这些功能的作用......:P 感谢您的出色帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多