在 SQL Server 中将记录的状态设置为 false 之前检查记录的子记录

Posted

技术标签:

【中文标题】在 SQL Server 中将记录的状态设置为 false 之前检查记录的子记录【英文标题】:Check child records of a record before making status of it as false in SQL Server 【发布时间】:2018-08-17 14:17:41 【问题描述】:

我的 SQL Server 数据库中有一个包含一些关系表的应用程序。

在应用程序中,每当用户删除和记录时,我从不将其从数据库中删除,而是将“状态”(表格列)设为“假”。

例如:用户将从tblAccounts 中删除一条记录,该记录有一个“状态”列,可以是真/假。删除操作记录时设置为 false。

现在的问题是此帐户可能会在其他交易中被引用。如果在其他表中使用,则不应允许用户删除(使其为 false)。

如果我允许用​​户从表中物理删除记录,它会抛出外键错误,但在这种情况下(使其为假)我如何检查子行而不删除并提示用户。

我可以通过对每个表的选择查询来做到这一点,但这会降低我的应用程序的速度。

还有其他方法/想法可以实现吗?

【问题讨论】:

我不太清楚你想要什么。更重要的是,您是否在使用此设置时遇到了问题,如果有,它们究竟是什么问题,或者您只是在猜测潜在的问题。 这个答案解释了一个调用 UDF 的检查约束,这可能是一个可能的解决方案。 --> ***.com/questions/13000698/… 我建议使用状态查找表而不是 True/False 字符串。老实说,对于一种身份来说,真假是没有意义的。也许 IsDeleted 会是一个更好的名称,然后使用 bit 数据类型。但我离题了。您是在问如何在 sql server 或您的应用程序中执行此操作吗?可悲的是,这个问题不是很清楚。我们可能还需要查看一些表定义和示例数据。 spaghettidba.com/2015/04/24/… 如果你想像硬删除一样防止软删除,你可以扩展外键来引用ID, Status,而不是仅仅引用ID(这需要这两个上的唯一索引列)。因为外键将始终将account_Status 设置为1(或True,我假设这是BIT,就像肖恩说的那样,应该真正命名为Deleted 并且它的含义颠倒了)你可以这样做具有常量0 值的持久计算列。通过这种方式,更新被阻止的方式与删除相同,但代价是为冗余数据占用了一些存储空间。 【参考方案1】:

我可以通过对每个表的选择查询来做到这一点,但这会变慢 我的申请。

还有其他方法/想法可以实现吗?

不,没有。您可以使用调用函数的 CHECK 约束或使用 TRIGGER 进行自动化,但在该代码中,必须执行针对其他表的 SELECT 语句。没有办法解决。

【讨论】:

【参考方案2】:

您可以使用外键来执行此操作,这里的技巧是在 tblAccounts 中将两个列(AccountID 和 Status)设为主要列。然后在事务表中,您创建一个外键(AccountID 和 Status),并在 UPDATE/Delete 时使用级联。这意味着,如果您从 tblAccounts 更改/删除帐户 ID 或其状态,这些更改也将应用于所有外键。

这是一个例子:

CREATE TABLE tblAccounts(
    ID INT,
    AccountID INT NOT NULL,
    [Status] BIT NOT NULL
)
ALTER TABLE tblAccounts
ADD PRIMARY KEY (AccountID, [Status])


CREATE TABLE tblTransactions(
       [ID] INT,
      [TransID]  INT NOT NULL PRIMARY KEY,
      [AcctID]   INT NOT NULL,
      [Status]   BIT NOT NULL
)
ALTER TABLE tblTransactions
ADD FOREIGN KEY (AcctID,[Status]) REFERENCES tblAccounts(AccountID, [Status])
ON UPDATE CASCADE
ON DELETE CASCADE 


INSERT INTO tblAccounts (ID, AccountID, [Status])
VALUES 
(1,1000,1), 
(2,1100,1),
(3,1200,1),
(4,1300,1)

INSERT INTO tblTransactions(ID, TransID, AcctID,[Status])
VALUES 
(1,5000,1000,1),
(2,3258,1300,1),
(3,5852,1000,1),
(4,9631,1100,1),
(5,1870,1200,1)

tblAccounts

| ID | AccountID | Status |
|----|-----------|--------|
|  1 |      1000 |   true |
|  2 |      1100 |   true |
|  3 |      1200 |   true |
|  4 |      1300 |   true |

tblTransactions

| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
|  1 |    5000 |   1000 |   true |
|  2 |    3258 |   1300 |   true |
|  3 |    5852 |   1000 |   true |
|  4 |    9631 |   1100 |   true |
|  5 |    1870 |   1200 |   true |

让我们将AccountID 1100的状态改为false

UPDATE tblAccounts
SET 
    [Status] = 0
WHERE 
    AccountID = 1100

检查 tblAccount

| ID | AccountID | Status |
|----|-----------|--------|
|  1 |      1000 |   true |
|  2 |      1100 |   false|
|  3 |      1200 |   true |
|  4 |      1300 |   true |

检查 tblTransactions

| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
|  1 |    5000 |   1000 |   true |
|  2 |    3258 |   1300 |   true |
|  3 |    5852 |   1000 |   true |
|  4 |    9631 |   1100 |   false|
|  5 |    1870 |   1200 |   true |

【讨论】:

感谢您的努力和回答,但不应继续更新 tblaccounts。外键的其他选项可以解决问题吗? @user10239717 外键与其父键(主键)相关。对父级的任何更改也会影响其子级。因此,如果不对主键(即 tblaccount 上的状态)进行更改,它将无法工作。您可以使用相同的方法,但使用不同的列(也许是新的?)

以上是关于在 SQL Server 中将记录的状态设置为 false 之前检查记录的子记录的主要内容,如果未能解决你的问题,请参考以下文章

在sql server中将行/表记录转换为json文档

在 SQL Server 中将身份设置为打开或关闭

如何在 SQL Server 中将函数设置为默认值?

如何在 SQL Server Management Studio 中将列值设置为 NULL?

当用户在 MS Access 中修改表中的另一列时,如何在 SQL Server 中将列设置为今天的日期 [关闭]

Sql Server怎样设置sa用户登录