RDBMS 建模:具有极端历史版本控制的多对多
RDBMS Modeling: Many to Many with Extreme Historical Versioning
您有两个 table,foo
和 bar
,它们具有 M:N
关系。
您想维护 foo
和 bar
的非常极端的历史版本,以及它们之间的关系,例如:
你在Foo
中插入一行,然后在Bar
中插入一行,然后在FooBar
中插入一行linking两人在一起。您应该能够及时回顾并看到 Foo
中的行曾经是独立的,Bar
.
中的行也是如此
然后将另一行插入 Bar
,然后将一行插入 FooBar
link 将第二个 bar
插入第一个 foo
。您应该能够及时回顾并看到 foo
行仅 linked 到第一个 bar
行。
然后您更新 foo
行的属性之一。您应该能够及时回顾并看到 Bar
中的两行都曾经 linked 到具有先前属性的 foo
行。
虽然我能够实现这个,但我的解决方案相当乏味,并且会导致单个 update/insert 的大量 DML 操作。在 Bar 和 Baz 之间添加一个带有 M:N 的 Baz table 会显着增加 DML 的数量。是否有比以下方法更好地完成此任务的标准方法?
这是我的解决方案:
DDL
Foo
--------------
foo_id INT --sequence generated
foo_version_id INT UNIQUE --sequence generated
foo_name VARCHAR
active INT CHECK (active in (0,1))
CONSTRAINT PRIMARY_KEY (foo_id, foo_version_id)
Bar
--------------
bar_id INT --sequence generated
bar_version_id INT UNIQUE --sequence generated
bar_name VARCHAR
active INT CHECK (active in (0,1))
CONSTRAINT PRIMARY_KEY (bar_id, bar_version_id)
FooBar
--------------
foo_version_id FK to foo.foo_version_id
bar_version_id FK to bar.bar_version_id
CONSTRAINT PRIMARY KEY (foo_version_id, bar_version_id)
DML
以下是三种情况的伪代码。我已将这些作为程序实施。
对于案例#1,这导致对 link 两个独立的 foo
和 bar
进行 4 次 DML 操作,不包括前两行:
Insert the first foo row
Insert the first bar row
Update the first foo row and set active to 0.
Insert a new foo row with the same foo_id, foo_name, but new foo_version_id
Update the first bar row and set active to 0
Insert a new bar row and with the same bar_id, bar_name, but new bar_version_id
Insert a row into foo_bar with the foo_version_id and bar_version_id from the newly created active foo and bar rows.
对于 案例 #2,这导致 9 个 DML 操作 link 一个新的 bar
到 foo
即 linked 到第一个 bar
,不包括第一行:
Insert the second bar row
Update the active foo and set active to 0
Insert a new foo row with same foo_id, foo_name, but new foo_version_id
Update the first active bar and set active to 0
Insert a new bar row with same bar_id, bar_name, but new bar_version_id
Update the second active bar and set active to 0
Insert a new bar row with same bar_id, bar_name, but new bar_version_id
Insert a row into foo_bar with the foo_version_id and bar_version_id from the foo and first bar.
Insert a row into foo_bar with the foo_version_id and bar_version_id from the foo and second bar.
对于案例#3,这会导致 8 个 DML 操作来更新 foo
上的一个属性,linked 为两个 bars
:
Update the active foo and set active to 0
Insert a new foo row with same foo_id, but new foo_version_id, foo_name
(repeat from case #2 starting at line 4)
SQL
给定一个已知的 foo_id
,我可以在 foo_version_id
和 bar_version_id
上加入 foo
、foo_bar
、bar
并查看每个所讨论的特定 foo 的可能历史状态。
select f.foo_id, f.foo_version_id, f.foo_name, b.bar_id, b.bar_version_id, b.bar_name
FROM foo f, foo_bar fb, bar b
WHERE 1 = 1
AND f.foo_version_id = fb.foo_version_id (+)
AND fb.bar_version_id = b.bar_version_id (+)
ORDER BY f.foo_version_id, b.bar_version_id
;
foo_id | foo_version_id | foo_name | bar_id | bar_version_id | bar_name
1 | 1 | a | | | -- 1) independent foo
1 | 2 | a | 1 | 2 | b -- 2) link foo to first bar
1 | 3 | a | 1 | 4 | b -- 3) link second bar to foo
1 | 3 | a | 2 | 5 | b2 -- 3) link second bar to foo
1 | 4 | A | 1 | 6 | b -- 4) rename foo_name to A
1 | 4 | A | 2 | 7 | b2 -- 4) rename foo_name to A
您需要一个时态数据库,即支持 SQL:2011 时态(或类似的专有系统)
据我所知,没有开源数据库支持这一点。一段时间以来,我一直在缠着 Posgres 的人去做这件事。
这意味着您需要 shell 拿出一些现金。以下数据库支持它:
IBM DB2 10+
甲骨文 12c
微软 SQL 服务器 2016
您有两个 table,foo
和 bar
,它们具有 M:N
关系。
您想维护 foo
和 bar
的非常极端的历史版本,以及它们之间的关系,例如:
你在
Foo
中插入一行,然后在Bar
中插入一行,然后在FooBar
中插入一行linking两人在一起。您应该能够及时回顾并看到Foo
中的行曾经是独立的,Bar
. 中的行也是如此
然后将另一行插入
Bar
,然后将一行插入FooBar
link 将第二个bar
插入第一个foo
。您应该能够及时回顾并看到foo
行仅 linked 到第一个bar
行。然后您更新
foo
行的属性之一。您应该能够及时回顾并看到Bar
中的两行都曾经 linked 到具有先前属性的foo
行。
虽然我能够实现这个,但我的解决方案相当乏味,并且会导致单个 update/insert 的大量 DML 操作。在 Bar 和 Baz 之间添加一个带有 M:N 的 Baz table 会显着增加 DML 的数量。是否有比以下方法更好地完成此任务的标准方法?
这是我的解决方案:
DDL
Foo
--------------
foo_id INT --sequence generated
foo_version_id INT UNIQUE --sequence generated
foo_name VARCHAR
active INT CHECK (active in (0,1))
CONSTRAINT PRIMARY_KEY (foo_id, foo_version_id)
Bar
--------------
bar_id INT --sequence generated
bar_version_id INT UNIQUE --sequence generated
bar_name VARCHAR
active INT CHECK (active in (0,1))
CONSTRAINT PRIMARY_KEY (bar_id, bar_version_id)
FooBar
--------------
foo_version_id FK to foo.foo_version_id
bar_version_id FK to bar.bar_version_id
CONSTRAINT PRIMARY KEY (foo_version_id, bar_version_id)
DML
以下是三种情况的伪代码。我已将这些作为程序实施。
对于案例#1,这导致对 link 两个独立的 foo
和 bar
进行 4 次 DML 操作,不包括前两行:
Insert the first foo row
Insert the first bar row
Update the first foo row and set active to 0.
Insert a new foo row with the same foo_id, foo_name, but new foo_version_id
Update the first bar row and set active to 0
Insert a new bar row and with the same bar_id, bar_name, but new bar_version_id
Insert a row into foo_bar with the foo_version_id and bar_version_id from the newly created active foo and bar rows.
对于 案例 #2,这导致 9 个 DML 操作 link 一个新的 bar
到 foo
即 linked 到第一个 bar
,不包括第一行:
Insert the second bar row
Update the active foo and set active to 0
Insert a new foo row with same foo_id, foo_name, but new foo_version_id
Update the first active bar and set active to 0
Insert a new bar row with same bar_id, bar_name, but new bar_version_id
Update the second active bar and set active to 0
Insert a new bar row with same bar_id, bar_name, but new bar_version_id
Insert a row into foo_bar with the foo_version_id and bar_version_id from the foo and first bar.
Insert a row into foo_bar with the foo_version_id and bar_version_id from the foo and second bar.
对于案例#3,这会导致 8 个 DML 操作来更新 foo
上的一个属性,linked 为两个 bars
:
Update the active foo and set active to 0
Insert a new foo row with same foo_id, but new foo_version_id, foo_name
(repeat from case #2 starting at line 4)
SQL
给定一个已知的 foo_id
,我可以在 foo_version_id
和 bar_version_id
上加入 foo
、foo_bar
、bar
并查看每个所讨论的特定 foo 的可能历史状态。
select f.foo_id, f.foo_version_id, f.foo_name, b.bar_id, b.bar_version_id, b.bar_name
FROM foo f, foo_bar fb, bar b
WHERE 1 = 1
AND f.foo_version_id = fb.foo_version_id (+)
AND fb.bar_version_id = b.bar_version_id (+)
ORDER BY f.foo_version_id, b.bar_version_id
;
foo_id | foo_version_id | foo_name | bar_id | bar_version_id | bar_name
1 | 1 | a | | | -- 1) independent foo
1 | 2 | a | 1 | 2 | b -- 2) link foo to first bar
1 | 3 | a | 1 | 4 | b -- 3) link second bar to foo
1 | 3 | a | 2 | 5 | b2 -- 3) link second bar to foo
1 | 4 | A | 1 | 6 | b -- 4) rename foo_name to A
1 | 4 | A | 2 | 7 | b2 -- 4) rename foo_name to A
您需要一个时态数据库,即支持 SQL:2011 时态(或类似的专有系统)
据我所知,没有开源数据库支持这一点。一段时间以来,我一直在缠着 Posgres 的人去做这件事。
这意味着您需要 shell 拿出一些现金。以下数据库支持它:
IBM DB2 10+
甲骨文 12c
微软 SQL 服务器 2016