【问题标题】:SQL: How do I design a versioned key:value pair, allowing for non-unique values?SQL:如何设计版本化的键:值对,允许非唯一值?
【发布时间】:2020-06-17 05:34:39
【问题描述】:

我正在寻找有关如何以任何 SQL 风格实现版本化 key:val 对的建议。

(我们现在假设 SQlite 和 Postgres。)

我有一张表,初步是这样的:

locale key version -> value

语言环境和键构成原始未版本化的候选/主键。添加版本以允许存储多个版本。

棘手的部分是源数据中的“更新”(我无法控制)可能会在不更改值的情况下增加版本号。在这些情况下,我想禁止增加版本号。

但是,我不能规定该值是唯一的,因为我希望允许值切换,例如

en_US key1 1 -> "hello world"
en_US key1 42 -> "henlo world"
en_US key1 57 -> "hello world"

是一个有效的序列:错误被意外引入然后回滚。保留大约 42 版的数据很重要。

但是,我们可能经常发现源数据的版本 58 不会更新键的值 - 所以这是“最后修改”版本语义。

例如以下是无效序列:

en_US key1 57 -> "hello world"
en_US key1 58 -> "hello world"

为保留“上次修改”语义,不应添加版本 58 条目。

我可以进行“插入 if”样式检查并查询语言环境/键的最新版本是否与收到的版本匹配,但我担心这会使我面临竞争条件。

在 sqlite/postgres 中有没有更基本的方法来模拟这个约束?我不确定这种约束在形式上被称为什么。 (这不是很“独特”。)

【问题讨论】:

  • “我担心比赛条件” - 怎么回事?
  • 我很好奇这一切的应用。我的第一个想法是一个 UPSERT,即 INSERT 如果新行与最后一行具有相同的内容,它将失败。在 Postgres 中,您添加一个 ON CONFLICT UPDATE 子句来捕获失败的 INSERT 并改为执行 UPDATE。如何在没有唯一约束的情况下使INSERT 失败,我不确定。也许是CHECK 约束。
  • 好问题 - 源数据是版本化的,但我需要编译历史以便可以调用/使用过去的版本。版本之间的大集合中没有多少键更改,因此希望保持“已更改”版本语义。可能有一种更基本的方法可以做到这一点,但版本本身对客户有用,不能在内部任意。

标签: sql postgresql sqlite


【解决方案1】:

您提到的约束是业务规则。这是一个完美的逻辑需求示例,无法在关系模式中整齐地编码。您的规则似乎是“对于由键和语言环境标识的给定记录,系统应拒绝插入值与最新值相同的插入”。

大多数数据库约束旨在对表之间的标识或关系或属性可能具有的数据类型进行建模。业务规则可能与这些问题一致(例如“所有电话号码必须是唯一的”),但这不是关系约束的主要目的。

因此,我将在您实现任何其他业务规则时实现这一点,方法是在应用程序逻辑中、在您的 SQL 语句中或通过表上的触发器进行验证。

【讨论】:

  • 我支持这一点,没有办法使用普通的 SQL 约束来实现这一点。如果您使用的是 Postgres,我会使用 BEFORE INSERT 触发器,如果​​值自上一个版本以来没有更改,则返回 null 以使插入静默失败
  • 好的,有道理。应用程序逻辑或触发器它是。我并不总是精通现代 SQL 实现特性,而且我总是试图集中尽可能多的逻辑。我会放手的! (我想我只需要确保我的读写是原子的。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
相关资源
最近更新 更多