对一个完全标准化的表进行非规范化

时间:2013-03-19 12:34:47

标签: sql normalization multiple-tables denormalization

有人可以建议如何对一个完全规范化的表进行非规范化吗?尽管谷歌搜索,我仍然无法找到它。

每当记录被更新(虽然没有插入,但现在不用担心)在TableA中,记录将被插入到HistoryOfTableA中,其中包含已更改的字段的值以及执行时的相关时间戳。

例如

TableA字段:

TableA_Id, FieldA, FieldB, FieldC, FieldD.... etc

HistoryOfTableA记录:

HistID, TableA_Id, FieldChanged, OldValue, NewValue, DateCreated
1, 1, 'FieldA', 1, 2, <2013-03-18 12:20:00>
2, 1, 'FieldB', A, B, <2013-03-18 12:20:00>
3, 1, 'FieldC', A, B, <2013-03-18 12:20:00>

情况是我正在寻找创建一些SQL用于报告目的。所以我希望能够指定一个时间点,并能够将那些主机表条目汇总在一起,并计算出当时TableA中该记录的状态。

我想我可以根据历史记录表创建表格,并加入创建日期和表格A中的Id

例如

select HistA.NewValue, 
       HistB.NewValue, 
       .... 
from FieldA_HistoryOfTableA HistA 
     inner join FieldB_HistoryOfTableA HistB on HistA.DateCreated = HistB.DateCreated
       and HistA.TableA_Id = HistB.TableA_Id 
     inner join ... etc
where HistA.FieldChanged = 'FieldA'
and HistB.FieldChanged = 'FieldB'
and .... etc...

但我不认为这会给我所有我想要的东西,而我可能无法在SQL中完全做到这一点。另外,TableA中有20个字段,因此尝试加入20个表可能并不明智。

3 个答案:

答案 0 :(得分:2)

你的问题不在于表格是否正常化,而是表格不是。

由一个表中的字段标识的数据由另一个表中的数据标识,这使得查询非常复杂。

完全规范化的版本还会将TableA中的字段存储在单独的表中:

TableA
------------
TableA_Id

TableAFields
-------------
TableA_Id
FieldId
Value

Field
---------
FieldId
FieldName

HistoryOfTableA
----------------
TableA_Id
FieldId
OldValue
ChangedDate

现在您可以加入历史记录表中的字段。这将有点棘手,但至少它不会是20个连接的查询。

答案 1 :(得分:1)

如果您想要历史记录表中的最新记录,可以使用以下SQL:

select ht.*
from (select ht.*,
             ROW_NUMBER() over (partition by FieldChanged, TableA_Id order by DateCreated desc) as seqnum
      from HistoryOfTableA ht
      where datecreated <= YOURDATEHERE
     ) ht
where seqnum = 1

如果您希望将其作为单个记录,则应该转动或进行聚合。以下是后一种方法:

select ht.TableA_id,
       max(case when FieldName = 'FieldA' then NewValue end) as FieldA,
       . . .
from (select ht.*,
             ROW_NUMBER() over (partition by FieldChanged, TableA_Id order by DateCreated desc) as seqnum
      from HistoryOfTableA ht
      where datecreated <= YOURDATEHERE
     ) ht
where seqnum = 1
group by TableA_id

答案 2 :(得分:-1)

您可以尝试使用TableA中的XML列来记录TableA中每一行的历史记录。即每行都有一个XML类型的列,并记录该行的历史记录。然后你可以将行拉入你的应用程序(如果行数很大,则以批量方式),并找出TableA中每条记录的历史记录