处理我希望包含可空列的复合主键的表

时间:2011-08-07 12:20:57

标签: relational-database

假设一个表格如下:

userId INT (foreign key to a users table)
profileId INT (foreign key to a profiles table)
value INT

假设在此表中保存了用户的首选项。应根据当前用户和当前用户选择的配置文件加载首选项。这意味着userIdprofileId的组合是唯一的,可以用作复合主键。

但是,我希望添加能够保存默认值的功能,如果在数据库中没有保存特定profileId的值,则应该使用该默认值。我的第一个想法是将profileId列设置为可为空,并将null为profileId的行包含默认值。但是我不能使用涉及此表的复合主键,因为nullable columns can't be part of a primary key

那么解决这个问题的“最佳”方法是什么?只需完全放下主键而不使用主键?生成一个标识列作为我从不需要的主键?创建一个虚拟配置文件以链接到配置文件表中?为默认值创建一个单独的表(这是保证没有userId有多个默认值的唯一选项吗?)

更新:我考虑过Dmitry的答案,但毕竟它的缺点是我甚至无法在userId和profileId两列上创建唯一约束(如果profileId为null,MySQL将允许重复值,DB2将拒绝均等在可空列上创建唯一约束。因此,对于Dmitry的解决方案,我必须在没有DB的一致性检查的情况下生活。那可以接受吗?或者这是不可接受的(毕竟一致性检查是关系数据库的一个主要特征)。你的推理是什么?

4 个答案:

答案 0 :(得分:2)

  1. 为您的主键创建ID自动增量字段。
    1. 为(userId,profileId)对创建唯一索引。如有必要,创建虚拟配置文件而不是null。

答案 1 :(得分:2)

德米特里的答案很好,但由于你的案例涉及的本质上是一个交叉表,还有另一种解决这个问题的好方法。对于您的情况,我也喜欢创建默认用户配置文件的想法,您可以在代码中使用它来建立默认设置。这很好,因为它可以保持您的数据模型清洁,而不会引入额外的候选键。你需要在这个虚拟/默认配置文件中清楚这是它的本质。您可以给它一个明确的名称,如“默认用户”,并确保除管理员之外的任何人都无权访问用户凭据。

此解决方案的另一个优点是,您可以作为默认用户登录,并使用系统的GUI修改默认值,而不必通过数据库访问工具来调整数据。根据您商店中的策略,程序员直接访问数据表可能很难或不可能。使用经过测试/批准的GUI修改默认值可以消除大量繁文缛节并防止对数据造成某些意外损坏。

底线:主键非常重要。在事务系统中,每个表都应至少有一个唯一索引,其中一个索引应该是主键。您始终可以通过向每个表添加代理(自动增量)键来强制执行此操作。即使你这样做,你仍然通常需要一个自然唯一索引。这就是您通常会在表格中找到所需内容的方式。

在用户表格中创建默认用户条目不是作弊或黑客攻击,它使用您的表格结构就像它的使用方式一样,它允许您放置一个无论您是否使用代理键发明额外的任意唯一约束,都可以在用户ID和配置文件ID 的组合上使用唯一约束。

答案 2 :(得分:1)

这是UNIQUE列上NULL约束的正常行为。它允许一行数据具有NULL值。但是,这不是我们对此列所需的行为。我们希望列接受唯一值并接受多个NULL值。

这可以使用计算列并在计算列中添加约束而不是默认空值来实现。

请参阅以下文章将在此方面为您提供更多帮助:

UNIQUE Column with multiple NULL values

答案 3 :(得分:0)

我总是总是在表上使用主auto_increment键,即使它是多余的;它只是给我一个非常简单的方法来识别我想要稍后访问的记录或参考其他地方。我知道它并没有直接回答你的问题,但它确实使主键情况变得更简单。

create table UserProfile ( int UserProfileID auto_increment primary key etc., 
    UserID int not null, ProfileID int );

然后创建一个二级索引UserProfileIDX(UserID,ProfileID),它是唯一的,但不是主键。