【问题标题】:Get list of primary keys deleted in mysql获取mysql中删除的主键列表
【发布时间】:2012-07-12 21:41:06
【问题描述】:

我有一个父表 A 具有以下属性(列){ PKA, a1, a2...} 和子表 B 具有以下属性 {FKA, b1, b2...} PKA 是表 A 的主键(自增),表 B 没有任何主键,但它有一个外键列 FKA,它引用表 A 的 PKA 列(1:n 关系)

添加条目: 当我在表 A 中添加一个条目时...我使用 PDO API lastInsertId() 来插入记录并使用此值在表 B 中填充 FKA。

问题: 1. 但是,在删除条目时,我没有找到可以以类似方式使用的 API 'lastDeleteId()'

更大的问题: 当我的删除发生在表 A 上时,根据设计,删除命令是: DELETE from table A where a1 = 。此 a1 列是非唯一的,因此 DELETE 命令可以返回需要从表 B 中刷新的多个 PKA 键

注意事项:

  1. 我正在使用 PDO API
  2. MySQL 表(此处正在考虑)是 InnoDB
  3. 我在事务模式下运行(beginTransaction() 和 commit()/rollback() 之间的多个 SQL 调用
  4. 不寻找 CASCADE ON DELETE 选项

感谢您的任何指点。

【问题讨论】:

  • 每张表都应该有一个PK,怎么才能唯一标识一条记录呢?这对于删除尤为重要。
  • @HLGEM 与您的肯定相反的一个反例是,多对多链接表不需要也不应该使用 PK,除非您将两个 FK 都用作多列 PK。
  • @HLGEM 这不一定是真的。其他列可用于删除记录。我特别不需要唯一标识表 B 中的记录。在我的情况下,将 PK 添加到表 B 是多余的
  • @HLGEM 我并没有建议 PK 是不必要的,我建议唯一标识一行并不总是通过一个列定义(在多对多表的情况下,我建议多列 PK);我的建议是,并非每个表都需要单列 PK。我觉得您的回复令人反感,并希望在事态升级之前在此结束(通过停止进一步的辩论)。
  • @HLGEM 无需点名即可表达您的观点。

标签: php mysql pdo


【解决方案1】:

您可以在删除查询之后立即使用此查询,也可以将其用作批量清理方法,该方法将追溯适用于未与依赖父级一起删除的任何子级:

DELETE
    FROM  table_a
    WHERE a1 = ?;
SELECT    id
    FROM  table_b
    WHERE FKA NOT IN(SELECT id FROM table_a);

或者您可以在删除查询之前使用相同的 WHERE 子句运行它:

START TRANSACTION;
    SELECT    id
        FROM  table_b
        WHERE FKA NOT IN(
            SELECT id
                FROM table_a
                WHERE a1 = ?;
        );
    DELETE
        FROM  table_a
        WHERE a1 = ?;
COMMIT;

第二种方法需要包含在事务中,以确保您只删除在选择时匹配的 id,即使其他线程可能已输入与这些过滤器匹配的新数据。

编辑 - 方法问题

如果您使用$pdo->beginTransaction(),然后发出一个SELECT 语句,获取ID,在应用程序级别使用它们,然后发出delete 语句,这将保持事务活跃和一些记录可能会被锁定在该事务中,特别是如果您在初始 select 语句中使用 FOR UPDATE 和/或如果您有较高的 ISOLATION LEVELs。

如果您在应用程序层使用耗时的操作,这将在数据库中长时间保持活动锁,并降低应用程序的并发连接容量。

我擅长避免与数据库服务器进行多次通信会话,只要一个就足够了。这就是为什么我一开始不会使用$pdo->beginTransaction()

我会将“获取要删除的 ID”查询扩展为“获取处理已删除记录所需的所有数据”。我会在事务中的一个通信会话中将查询发送到服务器,并且SELECT 状态的结果集将被发送回应用程序,即使当时数据已从存储中删除应用程序接收负载。

【讨论】:

  • 谢谢!我认为这可能有效..但考虑到大量记录,我认为这可能有点太贵了。如果没有更好的答案,我会选择你的答案!
  • 如果你有一个 FK,你永远不会先从父级删除,除非你使用 cascade delte。 FK 的目的是防止您在有子记录时删除父记录。
  • @HLGEM 如果您使用的是ON DELETE RESTRICT,但另一方面您可以使用ON DELETE CASCADE 也可以删除子行或ON DELETE SET NULL只是将孩子与(现已删除的)父母断开连接。
  • @MihaiStancu +1 为您解答
【解决方案2】:

您所做的是选择要删除的记录的记录 ID 并将它们放在临时表中。然后你首先从子表中删除,然后是父表。在事务中执行此操作,以便在出错时回滚数据。

【讨论】:

  • 这个答案+1。我没有使用临时表,而是在数组中执行了 pdo fetch() 并迭代该数组以首先删除子项,然后是父项
【解决方案3】:

我认为最简单的方法可能是将表 A 的内容复制到临时表中,然后执行删除,然后将临时表的 LEFT OUTER JOIN 到更新的表中,并使用它来查找不存在的行不再有对口。

另外,如果你没有明确地创建一个主键,InnoDB 不会在后台为你创建一个吗?我认为 InnoDB 存储引擎需要一个。

【讨论】:

  • 谢谢!问题不在于主键。作为事务的一部分,我收到以下命令:从表 A 中删除,其中 a1 = 某个值 1。这将删除表 A 中的一堆记录。我需要获取这些记录的 PKA 值。然后,我需要从获取 FKA = PKA 值的表 B 中附加 DELETE。所以问题是如何为已删除的记录获取这些 PKA 值......如果我把我的问题弄乱了,我很抱歉
  • 我告诉过你,你先选择它们并将它们放入临时表中,然后通过连接到临时表中删除。
【解决方案4】:

如何解决您的数据可能不一致的想法。也就是说,可能存在对已删除的 pk 的引用。每次使用 fk 时都检查一下。

然后添加一个计划任务来清理记录,方法是使用 select from where fk is not in (select pk) 检查。

【讨论】:

  • 感谢您的回答。我想将其作为交易的一部分来完成。考虑到我的应用程序,计划任务将是开销
猜你喜欢
  • 2013-11-04
  • 2011-01-07
  • 1970-01-01
  • 2014-08-30
  • 2015-04-05
  • 2011-11-19
  • 2012-03-03
  • 1970-01-01
  • 2019-02-16
相关资源
最近更新 更多