I have the following tables (taken out of a larger schema). It worked well for the intitial purpose (i.e., optionally map only the parent category
to the wallets_balance_history
table).
Now, there is a need to change this when we introduced sub-categories (i.e., categories level 1, and 2).
Essentially, I need to modify this schema such that I can query all the sub-categories (if any) for any single row in wallets_balance_history
table. The categories all are optional unless they a parent of a sub-category. That is, they can be null, or only parent category
, or both parent category
and category_level_1
, or all: category
, category_level_1
, and category_level_2
. But you can't have category_level_n without the parent category.
Option 1:
Add fk to wallets_balance_history
for every category level (i.e., add three columns mapped to the to the three category levels). It's the easiest, but does it follow the best practice? what if the number of categories grow.
Option 2:
Add bridge/lookup table between category
and wallets_balance_history
table, say bridge
. In this table I store the each category in separate rows, but all share the same bridge id. Then use that bridge id in wallets_balance_history
table. The bridge id won't be PK (since it will not be unique in bridge
Is there better, cleaner option? I want to be able to query the categories associated with the balance history without building complex if/else statements.
Don't use multiple tables.
Create one table and have a hierarchical data structure with a referential constraint that points to the primary key of the same table:
CREATE TABLE categories (
id NUMBER(10,0)
CONSTRAINT categories__id__pk PRIMARY KEY,
name VARCHAR2(200),
description VARCHAR2(4000),
wallet_id REFERENCES wallets (id),
parent_id REFERENCES categories (id),
user_id NUMBER(10,0),
status_id NUMBER(10,0),
type_id NUMBER(10,0),
created_by VARCHAR2(20),
created_on DATE,
updated_by VARCHAR2(20),
updated_on DATE,
CONSTRAINT categories__wi_xor_pi__nn CHECK (
(wallet_id IS NULL AND parent_id IS NOT NULL)
OR (wallet_id IS NOT NULL AND parent_id IS NULL)
)
)
The wallets_balance_history
can then point to the categories.id
column and, because there is only a single table, you do not need to worry about trying to add multiple columns or a bridging table.
If you then want to query the categories then use a hierarchical query.