Nella mia esperienza, quando gli sviluppatori cercano di rendere il loro sistema davvero "dinamico", in realtà stanno cercando di programmare per problemi a cui non hanno ancora pensato. Di solito è una brutta strada da prendere. È davvero così tanto lavoro extra per un modulo includere due tabelle invece di una?
In ogni caso in cui ho visto lo schema (o l'anti-modello?) di provare a creare un generico tavolo "fa tutto" è caduto a terra. Gli RDBMS funzionano meglio con aree problematiche ben definite. Se il modulo ha la necessità di conservare la cronologia, il modulo dovrebbe aggiungere una tabella della cronologia da abbinare alla tabella stessa. Questo ha anche un enorme vantaggio in quanto lungo la strada è probabile che tu voglia mantenere diversi tipi di informazioni nella cronologia a seconda della tabella o del modulo per cui viene conservata la cronologia. Se hai una tabella cronologica generica, diventa molto più difficile.
Ora, se vuoi semplicemente catturare l'ultimo utente per aggiornare o inserire un particolare elemento (riga di tabella) e che potrebbe trovarsi in più tabelle, puoi utilizzare un modello di ereditarietà in cui hai una tabella padre e più tabelle figli. Ad esempio:
CREATE TABLE Audited_Items
(
id INT NOT NULL IDENTITY,
CONSTRAINT PK_Audited_Items PRIMARY KEY CLUSTERED (id)
)
CREATE TABLE Articles
(
id INT NOT NULL,
[Article specific columns]
CONSTRAINT PK_Articles PRIMARY KEY CLUSTERED (id),
CONSTRAINT FK_Articles_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Media
(
id INT NOT NULL,
[Media specific columns]
CONSTRAINT PK_Media PRIMARY KEY CLUSTERED (id),
CONSTRAINT FK_Media_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Audit_Trail
(
audited_item_id INT NOT NULL,
audit_datetime DATETIME NOT NULL,
user_id INT NOT NULL,
[audit columns]
CONSTRAINT PK_Audit_Trail PRIMARY KEY CLUSTERED (audited_item_id, audit_datetime),
CONSTRAINT FK_Audit_Trail_Audited_Items FOREIGN KEY (audited_item_id) REFERENCES Audited_Items (id)
)