joh*_*kes 5 sql-server identity-column
我可以在多个表中使用"标识"(唯一,非重复)列吗?例如,假设我有两个表:书籍和作者.
Authors
AuthorID
AuthorName
Books
BookID
BookTitle
Run Code Online (Sandbox Code Playgroud)
BookID列和AuthorID列是标识列.我希望标识部分跨越两列.因此,如果存在值为123的AuthorID,则不能存在值为123的BookID.反之亦然.
我希望这是有道理的.
这可能吗?
谢谢.
我为什么要这样做?我正在写一个APS.NET MVC应用程序.我正在创建一个评论部分.作者可以发表评论.书籍可以有评论.我希望能够将实体ID(书籍ID或作者ID)传递给某个操作,并让该操作提取所有相应的注释.如果它是书籍或作者或其他什么,该行动将无关紧要.声音合理吗?
即使您可以将标识序列放在多个表中,您的注释表也无法在单个外键中引用这两个列.
就关系数据库设计理论而言,最好的方法是创建两个注释表.但显然,您可能希望避免这种情况,可能是出于代码重用的原因.
最直接的实用方法是在注释表上放置两个外键列,并为每个注释创建一个null,另一个不为null.
另一种方法可能是最好的妥协,就是这样.您在问题中提到"实体ID".所以制作实体表!然后作者,书籍和评论都可以参考该表.
编辑添加:
菲利普·凯利,雷,和(我认为)北极都建议通过添加修改意见表entity_id,它可以指的book_id还是author_id,和某种形式的标志(char(1),tinyint,和boolean,分别),指示-这几被提到.
由于许多原因(包括数据完整性,报告,效率)和理论原因,这不是一个好的解决方案.
第一个也是最明显的问题是数据完整性问题.关系数据库系统应始终负责维护其自身数据的完整性,并且DB有自然和首选的方法来实现此目的.这些机制中最重要的一个是外键系统.如果comment.entity_id列同时引用book.book_id和author.author_id,然后一个外键不能为此列创建.
当然,您可以检查您的DML(插入,更新,删除)存储过程以验证引用,但这很快就会变成一大堆,因为所有三个表上的所有DML操作都会涉及到.
这导致了我们的效率问题.每当对comment表运行查询时,它都需要连接到author或book表或两者.查询计划生成系统将没有可用于优化的外键,因此其性能很可能会降低.
然后在报告中存在该方案的问题.任何报告生成系统都会遇到这种系统的问题.对于专业程序员来说,这不会是一个问题,但任何用户临时报告都必须模仿event_id这个或那个意味着背后的逻辑,这可能是一个非常糟糕的交易.也许你永远不会在这个数据库上使用报告生成工具.但话说回来,没有人知道最终会使用数据库的位置.为什么不使用系统允许任何东西?
这导致我们理论上的问题.
在关系数据库理论中,每个表中的每一行(也称为"元组")("关系变量")代表关于现实世界的命题.设计表格是决定该命题的形式.让我们看几个如何工作的例子.
comment (comment_id int, comment_type char(1), entity_id int,
user_id int, comment_text nvarchar(max), comment_date datetime)
/* comment_id identifies a comment (comment_text) that a user (user_id)
has made about a book (entity_id if comment_type = 'B') or author
(entity_id if comment_type = 'A') at a particular date and
time (comment_date).*/
Run Code Online (Sandbox Code Playgroud)
这里很明显,所调用的列(或"属性")entity_id正在执行双重任务.除了引用另一列之外,它并不真正代表任何东西.这是可行的,但不能令人满意.
comment (comment_id int, book_id int, author_id int, user_id int,
comment_text nvarchar(max), comment_date datetime)
/* comment_id identifies a comment (comment_text) that a user (user_id)
has made about a book (book_id if not null) or author (author_id if
not null) at a particular date and time (comment_date). */
Run Code Online (Sandbox Code Playgroud)
这给我们买了第一个版本中最大遗漏的外键.但这仍然不是非常令人满意,除非一个评论可以同时引用一本书和一本作者(这可能是合理的).可空列是一个警告标志,表明设计出了问题,这也可能就是这种情况.如果不允许,则可能需要检查约束以避免引用任何内容的注释,或者引用书籍和作者的注释.
从理论的角度(因此,我的观点:))有一个明确的最佳选择:
book_comment (book_comment_id int, book_id int, user_id int,
comment_text nvarchar(max), comment_date datetime)
/* book_comment_id identifies a comment (comment_text) that a
user (user_id) has made about a book (book_id) at a particular
date and time (comment_date). */
author_comment (author_comment_id int, author_id int, user_id int,
comment_text nvarchar(max), comment_date datetime)
/* author_comment_id identifies a comment (comment_text) that a
user (user_id) has made about an author (author_id) at a particular
date and time (comment_date). */
Run Code Online (Sandbox Code Playgroud)
最后一个选项将提供最佳效率,数据完整性和易于报告.并且唯一的费用是DML存储过程需要将注释放入正确的表中,这不是什么大问题,因为他们必须知道评论所指的是什么.
如果您的计划是一次性检索书籍或作者的所有评论,那么您可以轻松地在这些表格之上创建一个视图,以再现其他设计,如果这是您想要做的.
create view comments as
select
book_comment_id as comment_id,
book_id as entity_id,
comment_text,
'B' as comment_type
from book_comment
union
select
author_comment_id as comment_id,
author_id as entity_id,
comment_text,
'A' as comment_type
from author_comment
Run Code Online (Sandbox Code Playgroud)
简短的回答是:不,你不能这样做(至少在 2008 年的 MS SQL Server 中)。
您可以创建一个新表“CommentableEntity”,将您的身份列插入其中,然后在 Authors 和 Books 中定义外键以将其作为父表引用,然后执行多种技巧之一来确保给定的 ID 值没有分配给两个表...但这是一个糟糕的主意,因为您构建的数据模型意味着作者和书籍是相关类型的数据,但实际上并非如此。
您可以有一个单独的表 Comments,其中包含标识列,并在 Authors 和 Books 中放置 CommentId 列。然而,这将限制每本书和作者只能发表一条评论。
我可能会在评论表中添加一个像“CommentorType”这样的列,并在其中放置一个标志来指示评论来源(“A”代表作者,“B”代表书籍)。在“CommentorId + CommentorType”上构建一个主键,它应该工作得足够好——随着系统的扩展,添加更多类型的评论者将是微不足道的。
| 归档时间: |
|
| 查看次数: |
3886 次 |
| 最近记录: |