我如何要求一个字段是免费的或付费的,但不能两者兼而有之?

How can I require a field to be either free or paid but not both?

我有免费和付费主题表。 免费主题已下载link 付费主题已购买 link 和价格。

这是图形格式的数据库模式:

一个主题不能既付费又免费。如何防止两个表(FreeThemes、PaidThemes)同时拥有一个主题的数据?

关于 亚型 的一句话。实现子类型约束的正确方法是使用断言(CREATE ASSERTION),但它在主要数据库中仍然不可用。我正在使用 FKs 代替,并且与所有其他替代方法一样,它并不完美。人们争论很多,关于 SO 和 SE-DBA,哪个更好。我鼓励您也检查其他方法。

-- Theme THM, of theme-type THM_TYP exists.
--
theme {THM, THM_TYP, -- other_common_attributes}
   PK {THM}
   SK {THM, THM_TYP}

CHECK THM_TYP in ('F', 'P')
-- Free theme THM (of theme-type 'F') exists.
--
free_theme {THM, THM_TYP,
           -- other attributes specific to free}
        
PK {THM}

FK {THM, THM_TYP} REFERENCES theme {THM, THM_TYP}

CHECK (THM_TYP = 'F')
-- Paid theme THM (of theme-type 'P') exists.
--
paid_theme {THM, THM_TYP,
           -- other attributes specific to paid}

PK {THM}

FK {THM, THM_TYP} REFERENCES theme {THM, THM_TYP}

CHECK (THM_TYP = 'P')

注:

All attributes (columns) NOT NULL


PK = Primary Key
AK = Alternate Key   (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

遵循正式的规范化规则不会让您得到这个解决方案。 free_themepaid_theme table 都有 FD {} --> {THM_TYP};换句话说,属性 THM_TYP 不依赖于 PK {THM},因此这些 table 在 2NF 中是 而不是

在这种情况下,FKCHECK 约束可防止异常和逻辑错误 -- 首先是规范化的 objective。

如果您对 table 不在 2NF 中有疑问,可以考虑以下方法:

  1. 确保free_themepaid_themetable处于高NF( 5NF) 没有 THM_TYP 属性。
  2. THM_TYP为了处理问题,理解妥协
  3. 请记住,问题的根本原因是在当前 SQL 实现中缺少所需的交叉 table 约束(断言)。

这是 Class table inheritance. 的一个示例,它是一个完全有效的设计选择(我不同意它是“规范化走得太远”)- 它是一种解决关系模型局限性的方法。

另一个限制是没有干净、本机的方式来声明您需要的业务规则。

有几种常见的方法可以解决这个问题。

首先是把责任委托给应用层。如果只有一个 application/service 连接到数据库,这并不可怕 - 特别是如果您可以将逻辑包装在单元测试等中。

二是将逻辑嵌入到触发器中。这允许您保证此业务规则,即使许多应用程序使用数据库,但您必须在业务逻辑更改时更改触发器(例如,如果您需要添加一个新的子class)。

最后一个选项是向主题 table 添加“类型指示符”,并使用该标志,而不是在子 class tables,确定主题是免费的还是付费的。同样,不是超级优雅,并且要求客户端应用程序遵守该标志,但它确实巧妙地表达了业务意图。

吻。两者一个 table -- 让价格为 0.00 表示免费。

(或者 NULL 可以表示“免费”,但我看不出有任何优势。)

主题中的新字段类型是或否(复选框)

如果是,那么“免费”;其他情况“已支付”