Denormalising a fully normalised table

£可爱£侵袭症+ 提交于 2019-12-25 03:49:26

问题


Can anyone advise on how to go about denormalising a fully normalised table? I've not been able to find much on it despite googling.

Whenever a record is updated (though not inserted, but lets not worry about that now) in TableA a record is inserted into HistoryOfTableA with the values of the fields which have changed and an associated timestamp when it was carried out.

eg.

TableA fields:

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

HistoryOfTableA records:

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>

The situation is I'm looking to create some SQL for reporting purposes. So I want to be able to specify a point in time, and be able pull together those hostory table entries and work out what the state of that record from TableA was at that time.

I'm thinking I can create tables based on the history table and joined on the date created and the Id from table A

eg.

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...

But I don't think this is going to give me all that I want and I may not be able to do this purely in SQL. As an aside there are 20 fields in TableA so trying to join 20 tables may not be wise.


回答1:


Your problem is not that the table is normalised, but rather that it isn't.

The data identified by fields in one table is identified by data in another table, which makes it very complicated to query.

A fully normalised version would also store the fields from TableA in a separate table:

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

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

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

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

Now you can join in the fields from the history table. That will be a bit tricky, but at least it won't be a query with 20 joins.




回答2:


If you want the most recent records from the history table, you can use the following 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

If you want this as a single record, you should either pivot or do an aggregation. Here is the latter approach:

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



回答3:


You can try using a XML column in the TableA to record the history of every row in TableA. i.e. Every row has a column which is of type XML and records the history of that row. Then you can pull the rows into your application(in a batched manner if the number of rows are huge), and find out the history of each record in TableA



来源:https://stackoverflow.com/questions/15499675/denormalising-a-fully-normalised-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!