从多个表中删除数据的正确方法是什么?


What is proper way to delete data from many tables?

当您想要删除一个类别时-它将首先删除所有具有相关组和属性的相关产品。一个产品有许多关系。

当删除一个类别时,它是这样处理的:

if (isset($_POST['catid']) && $_POST['catid'] > 0) {
    $category_id = mysql_real_escape_string($_POST['catid']);
    $SQL = "SELECT * FROM products WHERE category_id = '$category_id'";
    $q_item = mysql_query($SQL);
    while ($dItem = mysql_fetch_assoc($q_item)) {
        $itemid = $dItem['id'];
        $SQL = "SELECT * FROM option_groups WHERE item_id = " . $itemid;
        $q = mysql_query($SQL);
        while ($option_group = mysql_fetch_assoc($q)) {
            $optionGroup = $option_group['id'];
            $SQL = "SELECT * FROM options WHERE option_group_id = " . $optionGroup;
            $q = mysql_query($SQL);
            while ($row = mysql_fetch_assoc($q)) {
                $option = $row['id'];
                mysql_query("DELETE FROM options WHERE id = " . $option);
                mysql_query("DELETE FROM e_groups_options WHERE option_id = " . $option);
            }
            mysql_query("DELETE FROM option_groups WHERE item_id = " . $itemid);
            mysql_query("DELETE FROM products WHERE id = " . $itemid);
        }
    }
    $SQL = "DELETE FROM categories WHERE id = '$category_id'";
    mysql_query($SQL);
}

你可以看到,我已经使用了包括许多DELETE查询和代码看起来有点乱,有没有替代的方式和更安全?

存储引擎是MyISAM,我在表中有超过100,000行数据(字段被索引)。

如果这些表与外键相关,则可以在外键中指定ON DELETE CASCADE,然后删除Category。您必须切换到InnoDB才能应用此功能。引用外键的文档:

对于非InnoDB的存储引擎,MySQL Server解析CREATE TABLE语句中的FOREIGN KEY语法,但不使用或存储它

考虑到级联动作不会触发触发器。

你可以用ALTER TABLE table_name ENGINE = InnoDB把你的表切换到InnoDB。您可以使用ALTER TABLE语句添加外键,例如:

ALTER TABLE products
ADD FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE;

使用这个外键,每当您在categories上发出DELETE语句时,RDBMS也将删除引用该类别的products

由于您使用的是MyISAM,无法执行级联删除,因此您可以简单地执行连接删除。

DELETE table1, table2 FROM table1 LEFT JOIN table2 ON table1.id = table2.t1_id WHERE table1.id = $id

我认为最好的工作方式是使用一个支持外键约束的存储引擎(如InnoDB),并让它通过ON DELETE CASCADE来处理这个问题,这样DBMS就会为你做这项工作。

MyISAM目前还不支持外键

如果您不想或不能将数据库引擎更改为innodb,您可以使用join对多个表进行删除:

DELETE t1, t2, t3
FROM tabel1 AS t1
LEFT JOIN table2 AS t2 ON t1.id = t2.pid
LEFT JOIN table3 AS t3 ON t2.id = t3.pid
WHERE t1.id = $id

如果有一种方法可以连接所有想要从中删除行的表,则可以调整代码以执行这样的单个查询。

一个答案已经被接受了,但出于兴趣:如果您被卡在一个不进行级联删除的数据库上,您可以使用像Propel这样的ORM。我相信,可以配置为手动级联删除,它是不支持的db本地。