微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

审计表和外键

如何解决审计表和外键

我有一个包含多个必须审核的表的数据库

例如,我有一个用唯一 ID、名称和描述定义的对象表。

名称将始终相同。无法更新它。 “ObjectA”永远是“ObjectA”。

如您所见,名称数据库中不是唯一的,而只是在逻辑中。

行“from”、“to”和“creator_id”用于审核更改。 “from”是更改日期,“to”是添加新行的日期,如果是最新行则为空。 “creator_id”是进行更改的用户的 ID。

+----+----------+--------------+----------------------+----------------------+------------+
| id |   name   | description  |         from         |          to          | creator_id |
+----+----------+--------------+----------------------+----------------------+------------+
|  1 | ObjectA  | My object    | 2021-05-30T00:05:00Z | 2021-05-31T05:04:36Z |         18 |
|  2 | ObjectB  | My desc      | 2021-05-30T02:07:25Z | null                 |         15 |
|  3 | ObjectA  | Super object | 2021-05-31T05:04:36Z | null                 |         20 |
+----+----------+--------------+----------------------+----------------------+------------+

现在我有一个表,它必须有一个基于“唯一”对象名称的对象表的外键。

+----+---------+-------------+
| id |   foo   | object_name |
+----+---------+-------------+
|  1 | blabla  | ObjectA     |
|  2 | wawawa  | ObjectB     |
+----+---------+-------------+

如何在这两个表之间创建此链接

我已经尝试使用 uuid 创建另一个表并在对象表中添加一列“unique_identifier”。然后外键将链接到这个 uuid 表而不是对象表。问题是我有多个表有这个问题,我将不得不创建双倍的表。

也可以使用对象 ID 作为 FK 而不是名称,但这意味着在更新对象时,我必须使用新 ID 用该 FK 更新每个表。

解决方法

根据 SQL 标准,外键必须引用父表的主键或唯一键。如果主键有多个列,外键的列数和顺序必须相同。因此外键引用父表中的唯一行;不能有重复。

另一种解决方案是使用触发器,您可以在插入另一个表之前检查对象表中的对象是否存在。

更新:添加代码

准备表并创建触发器:(为了简单起见,我只在对象表中包含了 3 列。在触发器中,我只是在其他部分打印错误,您可以使用 RAISEERROR 函数引发错误以将错误返回给客户端)

  Create table AuditObjects(id int identity (1,1),ObjectName varchar(20),ObjectDescription varchar(100) )
    Insert into AuditObjects values('ObjectA','description ObjectA Test')
    Insert into AuditObjects values('ObjectB','description ObjectB Test')
    Insert into AuditObjects values('ObjectC','description ObjectC Test')
    Insert into AuditObjects values('ObjectB','description ObjectB Test')
    Insert into AuditObjects values('ObjectB','description ObjectB Test')
    Insert into AuditObjects values('ObjectA','description ObjectA Test')
    
    Create table ObjectTab2 (id int identity (1,foo varchar(200),ObjectName varchar(20))
    go
    
    CREATE TRIGGER t_CheckObject ON ObjectTab2 INSTEAD OF INSERT
    AS BEGIN
        
        Declare @errormsg varchar(200),@ObjectName varchar(20)
        select @ObjectName = objectname from INSERTED
        if exists(select 1 from AuditObjects where objectname = @ObjectName)
        Begin
            INSERT INTO ObjectTab2 (foo,Objectname)
            Select foo,Objectname
            from INSERTED
        End
        Else
        Begin
            Select @errormsg = 'Object '+objectname+ ' does not exists in AuditObjects table'
            from Inserted
    
            print(@errormsg)
        End
        
    END;

现在,如果您尝试在 ObjectTab2 中插入一行,对象名称为“ObjectC”,则将允许插入,因为“objectC”存在于审计表中。

Insert into ObjectTab2 values('blabla','ObjectC')
Select * from ObjectTab2

id          foo    ObjectName
----------- ------ --------------------
1           blabla ObjectC

但是,如果您尝试输入“ObjectD”,它不会进行插入并在输出中给出错误信息。

Insert into ObjectTab2 values('Inserting ObjectD','ObjectD')
Object ObjectD does not exists in AuditObjects table

好吧,这不是您所要求的,而是为您提供相同的功能和结果。

,

您不能继续根据“对象名称”链接两个表吗?唯一的区别是 - 当您连接两个表时,您将从 table1(您引用的第一个表)中获得多条记录。然后,您可以根据自己的要求添加基于 from 和 to 的过滤条件。

帖子编辑 - 我的意思是,在这种情况下,你仍然可以在不引入外键的情况下达到预期的效果-

让我们调用您的表 - Table1 和 Table2

--Below will give you all records from Table1
SELECT T2.*,T1.description,T1.creator_id,T1.from,T1.to 
FROM TABLE2 T2 
INNER JOIN TABLE1 T1 ON T2.OBJECT_NAME = T1.NAME;

--Below will give you ONLY those records from Table1 whose TO is null
SELECT T2.*,T1.to 
FROM TABLE2 T2 
INNER JOIN TABLE1 T1 ON T2.OBJECT_NAME = T1.NAME
WHERE T1.TO IS NULL;
,

我决定用一张额外的桌子来完成这个最终设计:

表“对象”

+-------+--------------------------------------+---------+--------------+----------------------+----------------------+------------+
| id PK |            identifier FK             |  name   | description  |         from         |          to          | creator_id |
+-------+--------------------------------------+---------+--------------+----------------------+----------------------+------------+
|     1 | 123e4567-e89b-12d3-a456-426614174000 | ObjectA | My object    | 2021-05-30T00:05:00Z | 2021-05-31T05:04:36Z |         18 |
|     2 | 123e4567-e89b-12d3-a456-524887451057 | ObjectB | My desc      | 2021-05-30T02:07:25Z | null                 |         15 |
|     3 | 123e4567-e89b-12d3-a456-426614174000 | ObjectA | Super object | 2021-05-31T05:04:36Z | null                 |         20 |
+-------+--------------------------------------+---------+--------------+----------------------+----------------------+------------+

表“Object_identifier”

+--------------------------------------+
|              identifier PK           |
+--------------------------------------+
| 123e4567-e89b-12d3-a456-426614174000 |
| 123e4567-e89b-12d3-a456-524887451057 |
+--------------------------------------+

表“foo”

+-------+--------+--------------------------------------+
| id PK |  foo   |         object_identifier FK         |
+-------+--------+--------------------------------------+
|     1 | blabla | 123e4567-e89b-12d3-a456-426614174000 |
|     2 | wawawa | 123e4567-e89b-12d3-a456-524887451057 |
+-------+--------+--------------------------------------+

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。