ForeignKey setup clarification on updating related fields
-
13-03-2021 - |
Question
Considering these two tables in PosgtreSQL:
# report
+----+-------------+--------------------+
| id | report_name | report_description |
+----+-------------+--------------------+
| 1 | RPT | ABCDEFGH |
| 2 | TST | LMNOPQRS |
+----+-------------+--------------------+
# report_years
+----+--------------+-------------+------+
| id | report_id_fk | report_name | year |
+----+--------------+-------------+------+
| 11 | 1 | RPT | 2019 |
| 12 | 1 | RPT | 2020 |
| 13 | 2 | TST | 2019 |
+----+--------------+-------------+------+
- Given that
report_id_fk
is a foreign key in thereport_years
table, there wouldn't be a way toCASCADE
and update thereport_name
based onreport_id_fk
? - They would have to be separate foreign keys?
report_name
shouldn't even be in thereport_years
table in the first place since it is redundant and should just be queried over with aJOIN
toreport
?- Is it possible to have a multifield foreign key constraint such that
report_name
andyear
would be required for aCASCADE
?
For example:
# report
+----+-------------+------+
| id | report_name | year |
+----+-------------+------+
| 1 | RPT | 2018 |
| 2 | RPT | 2019 |
| 3 | RPT | 2020 |
+----+-------------+------+
# report_details
+----+-----------+----------------+---------+---------+
| id | report_id | report_name_fk | year_fk | details |
+----+-----------+----------------+---------+---------+
| 11 | 1 | RPT | 2018 | ABC |
| 12 | 2 | RPT | 2019 | DEF |
| 13 | 3 | RPT | 2020 | GHI |
+----+-----------+----------------+---------+---------+
- If I wanted to change the
report_name
foryear = 2020
inreport
, it wouldCASCADE
toreport_details
and update thereport_name_fk
based on thereport_name_fk
andyear_fk
? - Or (back to question 1), can I setup a
CASCADE
that would updatedreport_name_fk
andyear_fk
inreport_details
?
I can see how to do this with a manual UPDATE
, but seeing if it is possible with CASCADE
. Or, like I think, this is redundant, should be avoided and if you need to know report_name
and year
for a report in report_details
, you should just write a query an JOIN
it.
Solution
You could solve this with a two-column foreign key and cascading update, but that requires a redundant two-column unique constraint on report
, which will harm DML performance and use extra storage space.
The proper solution is to remove the redundant column from report_years
. This concept of removing redundancy from a data model to improve consistency is so important that there is a name for it: normalization.