I’m designing SQL Server tables with Natural Keys instead of a Surrogate Keys for the Primary Key. The problem I’ve run into is that it doesn’t work well with the Audit table format that I’ve used with Surrogate Key tables in the past. Typically I’ll create an audit table that has the same columns as the table being audited. A trigger on the table being audited writes a new row to the audit table that matches the state of the row before update or delete. To enforce integrity I use both the Surrogate Key and modified date columns as a composite PK for the table. If I don’t use a Surrogate Key then I cannot track changes if one of the columns that make up the composite key changes.
Log table example with Surrogate Key:
LogId (PK)
LogType
Data
ModifedDate
ModifedBy
LogAudit Table for Log table with Surrogate Key:
LogId (PK)
LogType
Data
ModifedDate (PK)
ModifedBy
Log table example with Natural Key:
LogType (PK)
Data
ModifedDate (PK)
ModifedBy
LogAudit Table for Log table with Natural Key:
LogType
Data
ModifedDate
ModifedBy
How do you track changes for Natural Key Log table record in the Audit table if LogType or ModifiedDate change?
I think you misunderstood the basic concept here.
If it is true that
{LogType, ModifedDate}is a natural key in theLogtable (case 2), then it is also true that it is an alternate key (AK) (unique) in the first example.So the
Logtable in the first example would look like this.So, for a given
{LogID}the{LogType, ModifedDate}can not change, and vice versa.But, this is not what you are trying to accomplish. The answer is probably that your
Logtable does not have “natural key” in the first place.EDIT as per comments
As a rule-of-thumb, for creating a row-based audit table:
Copy the original table structure (columns).
Add
ChangedAt(datetime) andChangedBycolumns to the table.Add
ChangedAtcolumn to the original PK.Add copy of PK columns to the table. This is to capture any PK changes.
Add FKs with ON UPDATE CASCADE, ON DELETE NO ACTION. This prevents hard-deletes, so use soft deletes.
Populate from an AFTER INSERT, UPDATE trigger on the original table.
Example 1
Example 2
Example 3 (as per your description)