This question has come up a few times in various forums in my searching, but none have provided a concise resolution.
If I have the following tables:
User
+- id
+- username
+- password
Article
+- id
+- title
+- content
and I want to join them in order to determine who created what articles, I could simply add the column user_id to Article to use as a reference. Alternatively, I'm adding an intermediate table to show who/when/what, for example:
User
+- ...
Article
+- ...
ChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime
Now this is fine, but the system I'm working on needs to be much more dynamic, in that new modules can be easily introduced and integrated. So now if I add a Media table I need to split the ChangeHistory between Article and Media having:
User
+- ...
Article
+- ...
Media
+- id
+- title
+- path
ArticleChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime
MediaChangeHistory
+- id
+- media_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime
This can get out of hand quickly with the introduction of many modules. Each module would need to be responsible for the creation and management of it's own ChangeHistory table.
TL;DR: What practices can I explore to create an intermediate table that can receive references to multiple other unrelated tables? I could add a *record_type* field, holding the name of the table to which the record belongs, but that's ugly. I would need something like a "table ID" to reference the table from which it's coming. That way, when/if modules are added or removed, the model doesn't fall apart.
Any ideas? Thanks so much in advance.
The most common way to join two unrelated tables is by using CROSS join, which produces a cartesian product of two tables. For example, if one table has 100 rows and another table has 200 rows then the result of the cross join will contain 100x200 or 20000 rows.
You can have tables have refrence foriegn key to each other. But as others mention, you need to change you table creation script a bit.
Yes, you can! The longer answer is yes, there are a few ways to combine two tables without a common column, including CROSS JOIN (Cartesian product) and UNION. The latter is technically not a join but can be handy for merging tables in SQL. In this article, I'll guide you through the different solutions with examples.
No you can't.
In my experience, when developers try to make their system really "dynamic" they're actually trying to code for problems that they haven't thought of yet. That's usually a bad path to take. Is it really so much extra work for a module to include two tables instead of one?
In every case where I've seen the pattern (or anti-pattern?) of trying to make a generic "does everything" table it's fallen flat on its face. RDBMSs work best with well-defined problem areas. If the module has a need to keep history then the module should add a history table to go with the table itself. This also has a huge advantage in that down the road you're likely to want to keep different types of information in the history depending on the table or module for which the history is being kept. If you have a generic history table that becomes much more difficult.
Now, if you want to simply capture the last user to update or insert a particular item (table row) and that could be in multiple tables then you could use a pattern of inheritance where you have a parent table and multiple children tables. For example:
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)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With