您所描述的有时被称为“审计历史” - 它通常使用单个非规范化表来实现,但是当您失去强类型时,许多数据库纯粹主义者会反对它。
该表如下所示:
AuditTable( EventId bigint, DateTime datetime, Subject nvarchar, Table varchar, Column varchar, TablePK bigint, OldValueInt bigint nullable, OldValueStr nvarchar nullable )
-- add more nullable columns for more types, if necessary
每次更改值时,例如增加用户的声誉,您将在此表中添加一行,例如:
INSERT INTO AuditTable( Now(), N'User reputation increased', 'Users', 'Reputation', @userId, 100 )
您只需要存储旧值(更改前的值),因为新(即当前)值将在实际表行中。
使用 SQL Server 表触发器可以完全自动添加到审计表。
要查看用户的信誉历史记录,您可以执行以下操作:
SELECT * FROM AuditTable WHERE Table = 'Users' AND Column = 'Reputation' AND TablePK = @userId
现在正如我所说,这种设计更多的是用于审核而不是维护易于用户访问的历史记录,这些是缺点:
- 您无法对表进行语义索引,因此查找和列表总是很慢
- 您将数据库元数据存储为字符串,因此有很多开销
- 没有参照完整性(这可能是一件好事,因为如果您重新构建原始表,数据将保留,例如从用户表中删除 Reputation 字段)
如果你想更“纯粹”,那么你真的必须设计一个直接支持你想要构建的历史跟踪的表结构。您不需要为每个字段创建历史记录表 - 即使 Stackoverflow 也不会存储所有内容的历史记录。例如:
UserReputationHistory ( UserId bigint, ReputationChange int, DateTime when, Subject nvarchar )
当然,必须维护这些不同的 FooHistory 表确实会使您的代码复杂化。
您评论的原始问题中的其他内容,例如成员的加入日期不需要历史记录表,您可以从DateJoined
成员自己的数据库行中的字段中获取。