记录链接到任何表?

时间:2009-07-24 11:33:27

标签: sql key

嗨我在这方面有点挣扎,可以使用一些想法......

假设我的数据库有以下表格; 顾客 Supplers SalesInvoices 购买发票 货币

等等

我希望能够将“备注”记录添加到任何类型的记录

Notes表喜欢这个

NoteID        Int (PK)
NoteFK        Int
NoteFKType    Varchar(3)
NoteText      varchar(100)
NoteDate      Datetime

其中NoteFK是客户或供应商等的PK,而NoteFKType表示该注释针对哪种类型的记录

现在我意识到我无法添加一个引用多个表的FK,而不需要在所有表中都存在NoteFK。

那你怎么设计上面的? 注释FK必须位于上表中的任何一个

干杯, 丹尼尔

8 个答案:

答案 0 :(得分:3)

您必须接受无法向数据库讲授此外键约束的限制。所以你必须没有完整性检查(和级联删除)。

你的设计很好。 它可以轻松扩展到额外的表,每个实体可以有多个注释,目标表甚至不需要知道注释功能。

此设计相对于每个实体表使用单独的注释表的一个优点是,您可以轻松地跨所有注释运行查询,例如“最近的注释”或“由给定用户创建的所有注释”。

至于该表的参数变得过大,将其分成五个表会将表缩小到其大小的五分之一,但这对基于索引的访问没有任何影响。构建数据库是为了处理大表(只要它们被正确编入索引)。

答案 1 :(得分:2)

我认为你的设计没问题,如果你能接受这样一个事实,那就是db系统不会检查一个音符是否引用了其他表中的现有实体。这是我能想到的唯一一个不需要复制的设计,可以扩展到更多的表格。

您设计它的方式,当您添加您想要备注的其他实体类型时,您不必更改模型。此外,您不必在现有模型或其他表中包含任何其他列。

为确保数据完整性,您可以创建一组触发器或一些软件解决方案,偶尔会清理笔记表。

答案 2 :(得分:1)

在做你的建议之前,我会三思而后行。它在短期内可能看起来简单而优雅,但如果您真的对数据完整性和性能感兴趣,那么为每个父表提供单独的注释表是可行的方法。多年来,我使用其他答案(触发器,GUID等)中找到的解决方案来解决这个问题。我得出结论,增加的复杂性和性能损失是不值得的。通过为每个父表提供单独的注释表,并使用适当的外键约束,查找和连接将简单快速。将相关项组合到一个表中时,连接语法变得难看,并且您的注释表将变得庞大而缓慢。

答案 3 :(得分:1)

我同意Michael McLosky的学位。

我的想法是:拥有多个笔记表的技术成本是多少?

在我看来,最好将相同的功能合并到一个表中。它使报告和其他进一步发展更简单。更不用说保持表格列表更小,更容易管理。

这是一种平衡行为,你需要尝试预先确定这样做的好处和成本。我的个人偏好是数据库参照完整性。在我看来,完整性的应用程序管理应该受到业务逻辑的限制。数据库应确保数据始终一致且有效......


要真正回答您的问题......

我将使用的选项是使用用户定义函数检查值的检查约束。这适用于M $ SQL Server ...

CREATE TABLE Test_Table_1 (id INT IDENTITY(1,1), val INT)
GO
CREATE TABLE Test_Table_2 (id INT IDENTITY(1,1), val INT)
GO
CREATE TABLE Test_Table_3 (fk_id INT, table_name VARCHAR(64))
GO

CREATE FUNCTION id_exists (@id INT, @table_name VARCHAR(64))
RETURNS INT
AS
BEGIN
    IF (@table_name = 'Test_Table_1')
        IF EXISTS(SELECT * FROM Test_Table_1 WHERE id = @id)
            RETURN 1
    ELSE
    IF (@table_name = 'Test_Table_2')
        IF EXISTS(SELECT * FROM Test_Table_2 WHERE id = @id)
            RETURN 1

    RETURN 0
END
GO

ALTER TABLE Test_Table_3 WITH CHECK ADD CONSTRAINT
    CK_Test_Table_3 CHECK ((dbo.id_exists(fk_id,table_name)=(1)))
GO
ALTER TABLE [dbo].[Test_Table_3] CHECK CONSTRAINT [CK_Test_Table_3]
GO

INSERT INTO Test_Table_1 SELECT 1
GO
INSERT INTO Test_Table_1 SELECT 2
GO
INSERT INTO Test_Table_1 SELECT 3
GO
INSERT INTO Test_Table_2 SELECT 1
GO
INSERT INTO Test_Table_2 SELECT 2
GO
INSERT INTO Test_Table_3 SELECT 3, 'Test_Table_1'
GO
INSERT INTO Test_Table_3 SELECT 3, 'Test_Table_2'
GO

在该示例中,最终的插入语句将失败。

答案 4 :(得分:1)

您可以获得FK参照完整性,因为在每个其他表的notes表中有一列。

create table Notes (
    id int PRIMARY KEY,
    note varchar (whatever),
    customer_id int NULL REFERENCES Customer (id),
    product_id int NULL REFERENCES Product (id)
)

然后你需要一个约束来确保你只设置了一个列。

或者可能不是,也许您可​​能希望注释能够与客户和产品相关联。由你决定。

如果要添加另一个引用表,此设计需要向Notes添加新列。

答案 5 :(得分:0)

您可以向客户,供应商等表格添加GUID字段。然后在Notes表中,更改外键以引用该GUID。

这对数据完整性没有帮助。但它使得M-to-N关系可以轻松实现到任意数量的表,并且它使您不必在Notes表中定义NoteFKType列。

答案 6 :(得分:0)

您可以使用触发器轻松实现“多” - 外键。触发器将为您提供非常灵活的机制,您可以进行任何您希望的完整性检查。

答案 7 :(得分:-2)

为什么不以相反的方式执行此操作并在NotesID的其他表(客户,供应商等)中使用外键。这样您就可以进行一对一的映射。