【问题标题】:UNIQUE constraint controlled by a bit column由位列控制的 UNIQUE 约束
【发布时间】:2011-04-29 05:02:57
【问题描述】:

我有一张桌子,比如

FieldsOnForms(
 FieldID int (FK_Fields)
 FormID int (FK_Forms)
 isDeleted bit
)

这对 (FieldID,FormID) 应该是唯一的,但前提是该行未被删除 (isDeleted=0)。

是否可以在 SQLServer 2008 中定义这样的约束? (不使用触发器)

附:将 (FieldID, FormID, isDeleted) 设置为唯一可以将一行标记为已删除,但我希望有机会将 n 行(每个 FieldID、FormID)设置为 isDeleted = 1,并且只有一个与isDeleted = 0

【问题讨论】:

    标签: sql sql-server database-design unique-constraint


    【解决方案1】:

    您可以使用 SQL Server 2008 filtered indexes 功能拥有唯一的索引,或者您可以对视图应用唯一索引(穷人的过滤索引,适用于早期版本),但是你不能像你描述的那样有一个 UNIQUE 约束。

    过滤索引示例:

     CREATE UNIQUE NONCLUSTERED INDEX IX_FieldsOnForms_NonDeletedUnique ON FieldsOnForms (FieldID,FormID) WHERE isDeleted=0
    

    【讨论】:

    • 虽然我有一些错误,因为位字段(过滤索引不支持将列转换为常量的数据类型),这似乎是我想要的解决方案为。
    • @jaraics - 我刚刚在你的问题中创建了表格,然后在我的答案中创建了索引,它的创建没有错误。此外,如果您遇到数据类型不匹配,通常最好将常量转换(或转换)为列的类型,而不是相反。不确定这是否能解决您的问题。
    • 我忘了说 isDeleted 的默认值为 0,也许这就是区别。如果我 cast(0 as bit) 则创建索引,但我不能再从 SSMS 插入(但从脚本插入有效)
    • @jaraics - 是时候停止依赖 SSMS 提供的拐杖了,自己走吧 :-)
    • 似乎是 SQL Server 2008 R2 中的一个错误,它需要对过滤器中的值进行一段时间的 CAST。
    【解决方案2】:

    不,独特意味着真正独特。您要么必须将已删除的记录移动到另一个表,要么将 IsDeleted 更改为可以在所有已删除记录中唯一的内容(例如时间戳)。这两种解决方案都需要在您的应用程序、存储过程或触发器中进行额外的工作。

    【讨论】:

    • 他可以使用带有 WHERE 过滤器的唯一索引,所以这不是真的。
    【解决方案3】:

    您可以将 IsDeleted 列更改为 DeletedDate,并将其设置为 DATETIME,其中包含该行被逻辑删除的确切时间。或者,您可以添加一个 DeletedDate 列,然后针对该列创建一个 IsDeleted 计算列,以便在代码中使用该列时您仍然可以使用该列。然后,您当然会在 DeletedDate(除了 FieldID 和 FormId 之外)而不是 IsDeleted 列上放置一个唯一索引。那将只允许一个 NULL 列。

    Albin 发布了与此类似的解决方案,但随后将其删除。我不知道为什么,但如果他重新发布它,那么他在我之前就在这里了。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-17
      • 2021-12-09
      • 2017-08-05
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多