如何强制一个记录为布尔列的值为真,而所有其他记录为假值?

ema*_*ard 23 mysql database-design

我想强制一个表中只有一条记录被视为可能访问该表的其他查询或视图的“默认”值。

基本上,我想保证这个查询总是只返回一行:

SELECT ID, Zip 
FROM PostalCodes 
WHERE isDefault=True
Run Code Online (Sandbox Code Playgroud)

我将如何在 SQL 中做到这一点?

Nic*_*mas 10

注意:这个答案是在提问者想要一些 MySQL 特定的东西之前给出的。这个答案偏向于 SQL Server。

CHECK约束应用于调用UDF的表并确保其返回值 <= 1。UDF 可以只计算表 WHERE 中的行数isDefault = TRUE。这将确保表中不超过 1 个默认行。

您应该在列上添加位图过滤索引isDefault(取决于您的平台)以确保此 UDF 运行得非常快。

注意事项

  • 检查约束有一定的 局限性。也就是说,即使这些行尚未在事务中提交,也会为修改的每一行调用它们。因此,如果您启动一个事务,将新行设置为默认值,然后取消旧行的设置,您的检查约束会报错。那是因为它将在您将新行设置为默认值后执行,发现现在有两个默认值,并且失败。解决方案是确保在设置新默认值之前先取消设置默认行,即使您是在事务中执行此工作。
  • 正如gbn 指出的那样,如果您在 SQL Server 中使用快照隔离,UDF 可能会返回不一致的结果。但是,内联 UDF 不会遇到此问题,并且由于仅执行计数的 UDF 是可内联的,因此这不是问题。
  • 数据库引擎处理能力的优势在于它能够同时处理数据集。使用 UDF 支持的检查约束,引擎将被限制为将此 UDF 串行应用于修改的每一行。在您的用例中,您不太可能对PostalCodes表执行大量更新,但是对于可能基于集合的活动的那些情况,这仍然是一个性能问题。

考虑到所有这些警告,我建议使用gbn 建议的过滤唯一索引而不是检查约束。


gbn*_*gbn 9

编辑:在我们了解 MySQL 之前,这是面向 SQL Server 的

4 5 种方法可以做到这一点:按照最想要到最不想要的顺序

我们不知道这是什么 RDBMS,但不是所有的都适用

  1. 最好的方法是过滤索引。这使用 DRI 来保持唯一性。

  2. 具有唯一性的计算列(参见 Jack Douglas 的回答)(由编辑 2 添加)

  3. 索引/物化视图,类似于使用 DRI 的过滤索引

  4. 触发(根据其他答案)

  5. 使用 UDF 检查约束。这对于并发和快照隔离是不安全的。见一个 两个 三个 四个

请注意,“一个默认值”的要求是在表上,而不是存储过程。存储过程将具有与带有 udf 的检查约束相同的并发问题

注意:问了很多次: