如何检查子表正在使用/引用主表的记录

时间:2009-11-03 04:10:42

标签: sql master-detail

在我的ERP应用程序中,我将一个名为'IsRemoved'的额外字段作为布尔值。每当用户删除任何记录时,记录不会被删除 - 只有其“IsRemoved”列的值为'true'。它可以帮助我们在需要时恢复数据,并且工作正常。

问题在于,当用户删除主表的记录时,我们如何检查其所有子表都没有引用此记录(因为我们不进行物理删除,我们只将“isremoved”字段标记为true)?

请向我提供任何查询或sp,我可以检查主记录是否用于任何孩子。

5 个答案:

答案 0 :(得分:2)

根据经验,我必须告诉你这个设计很糟糕。考虑更改设计以将数据复制到“审计跟踪”表,然后将其从主表中物理删除。

如果您不考虑这一点,至少将其隐藏在VIEW并尽一切可能避免将此暴露给想要查询数据库的任何人,使用INSTEAD OF触发器必要时VIEW。否则,期望应用程序出现频繁的错误,因为有人忘记添加使用此表的每个查询所需的AND isremoved = 0谓词。

  

但这个'答案'并没有解决真正的问题。

是。抱歉,那个。但有时你必须治愈这种疾病,而不仅仅是治疗症状。

设计受到损害:表应该为单个实体类型建模,而这是建模两个。我该怎么说?因为OP已经声明,一旦'删除'实体有不同的数据要求,通过说“问题是......我们怎样才能检查所有子表没有引用此记录”。

所以'真正的'答案是:将实体移动到另一个不同的表。

但如果您从事治疗症状,那么这里就是答案:

  1. IsRemoved列添加到您的 所谓的'子'表,DEFAULT false并确保 它是NOT NULL
  2. 为每个约束添加CHECK约束 所谓的'孩子'表进行测试 isremoved = false(或其他什么 'boolean'在你的SQL中意味着 产物)。
  3. 添加复合键(例如使用 UNIQUEPRIMARY KEY) 所谓的“主人”表 (IsRemoved, <existing key columns here>),或更改现有密钥 相应地。
  4. 为每个约束添加FOREIGN KEY个约束 所谓'儿童'表可供参考 上面创建的复合键。

答案 1 :(得分:1)

我认为对问题本身的评论是非常恰当的。在这一点上,这个问题很模糊。

但是,假设子表还有一个IsRemoved字段 - 毕竟如果主记录被标记为已删除,则子记录的剩余可用点是什么? - 为什么不在Master上实现一个触发器,如果​​更改IsRemoved,还会更改Child上的IsRemoved标志?

这样就完全消除了检查孩子主人身份状态的需要,因为他们将处于同步状态,因为它与活动或非活动状态有关。

答案 2 :(得分:0)

您是否可以在事务中插入替换记录,其中除IsRemove ='true'以外的所有值都相同,然后删除原始记录?这将为替换记录生成新的主键,以便不能保留旧的引用。

我假设您希望检测子引用已删除记录的情况,并将其视为错误。

答案 3 :(得分:0)

如果我们使用以下查询在所有子表中放置了适当的外键约束,您可以找到引用的主数据表表:

SELECT uc.table_name MAIN_TABLE_NAME,
       ucc.column_name MAIN_TABLE_COLUMN_NAME,
       ucc_ref.TABLE_NAME AS REFERENCED_TABLE_NAME,
       ucc_ref.COLUMN_NAME AS REFERENCED_COLUMN_NAME,
       ucc_ref.position
FROM USER_CONSTRAINTS  uc,
     USER_CONS_COLUMNS ucc_ref,
     USER_CONS_COLUMNS ucc
WHERE uc.CONSTRAINT_TYPE = 'R'
  AND uc.R_CONSTRAINT_NAME = ucc_ref.CONSTRAINT_NAME
  AND ucc.Constraint_Name = uc.constraint_name
  AND  d ucc.table_name = uc.table_name
  AND ucc_ref.position = ucc.position
  AND uc.table_name = ? 
ORDER BY ucc_ref.TABLE_NAME,ucc_ref.column_name

此查询在oracle中有效。我不确定其他数据库。

找到引用的表后,您需要查找您尝试删除的主数据记录是否存在于引用的表中。如果子表中存在活动记录,则可以抛出异常。这里的关键是仅仅找到引用的记录是不够的。我们可能会遇到在子表中找到主记录引用的情况,但子记录也已被取消。我们使用上述概念编写了一个用于删除主数据预检查的工具。

答案 4 :(得分:-2)

使用此逻辑:

SELECT t1.*
FROM Table1 AS t1
WHERE NOT EXISTS
      ( SELECT *
        FROM Table2 AS t2
        WHERE t2.FKcolumn = t1.PKcolumn
          AND t2.columnX IS NULL
      )