2

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

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

请向我提供任何查询或 sp,我可以从中检查主记录是否在其任何子项中使用。

4

5 回答 5

2

根据经验,我不得不告诉你,这种设计很难使用。考虑更改设计以将数据复制到“审计跟踪”表,然后将其从主表中物理删除。

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

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

是的。对不起。但有时你必须治愈疾病,而不仅仅是治疗症状。

设计受到了影响:一个表应该对单个实体类型进行建模,而这是对两个实体类型进行建模。我怎么知道?因为 OP 已经声明一旦“删除”实体有不同的数据要求,通过说“问题是......我们如何检查它的所有子表都没有引用这条记录”。

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

但是,如果您从事治疗症状的业务,那么这里有一个答案:

  1. 将该列添加IsRemoved到您所谓的“子”表中,DEFAULT false并确保它是NOT NULL.
  2. CHECK为每个所谓的“子”表 添加一个约束以进行测试isremoved = false(或 SQL 产品中的任何“布尔”含义)。
  3. 将复合键(例如使用 UNIQUEor PRIMARY KEY)添加到您所谓的“主”表中 (IsRemoved, <existing key columns here>),或相应地更改现有键。
  4. FOREIGN KEY向每个所谓的“子”表添加约束以引用上面创建的复合键。
于 2009-11-03T10:34:17.523 回答
1

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

但是,假设子表也有一个 IsRemoved 字段 - 毕竟,如果主记录被标记为已删除,那么子记录仍然可用的意义何在?- 你为什么不在 Master 上实现一个触发器,如果​​ IsRemoved 改变了,也会改变 Child 上的 IsRemoved 标志?

这样,就完全不需要检查子节点的主节点状态,因为它们将同步,因为它与活动或非活动状态有关。

于 2009-11-03T06:00:16.557 回答
0

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

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

于 2009-11-03T04:30:56.720 回答
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 中有效。我不确定其他数据库。

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

于 2010-06-17T05:45:14.473 回答
-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
      ) 
于 2017-10-23T07:35:24.190 回答