Unless you have a good reason not to, you should normalize your database schema. When you normalize your database schema you are avoiding potential issues with data consistency that can occur when you have duplicated data.
Google the terms: insert anomaly, update anomaly, deletion anomaly. You will see lots of examples of the kinds of problems that an unnormalized database can cause.
Regarding modeling CONTRACT
separately from CAR
: I have found that one of the best places to start with a data model is to treat each tangible (or significant intangible) thing that your system cares about as its own table.
The hard reality is that business rules change, but the things that your business cares about don't change - at least not at nearly the same pace. Therefore, you want your data to reflect the reality of the things your business cares about.
People are not contracts. Sure, today your boss says one contract per person per car. What happens when your boss buys (or builds) a new parking garage and that car has a contract for both? What happens when one person sells a car that has a contract? The contract is signed by a person, not by the car? Does the contract go with the car or does it stay with the owner? What happens when your boss tells you he wants to start tracking future-dated contracts so that a car can have both its current contract and its contract for next year?
You don't have to normalize. You could try to get away with one big table for everything. You could just write everything down in a spreadsheet or on a piece of paper. However, if you want to build a system that is flexible for the future, then start by normalizing.
Regarding IDs for your tables: Never use anything external as the ID for something, unless you are totally positive that it will never change. A vehicle VIN is OK as an identifier. Nothing causes a VIN to change and it is guaranteed to be unique. A passport number is a terrible ID because (a) it will definitely change as time goes on and (b) you can't be sure that it will be unique. When primary keys change it causes all kinds of headaches. This is why a lot of people assign internal, meaningless surrogate keys to their tables.
EDIT: Something Else to Consider:
Something else you should consider is that you should NOT try to model (and maintain data for) things which aren't important to your system.
That is just making work for yourself now and down the road. Your system will be more complicated to build, maintain, upgrade and use.
Consider the following ERD:
The relationship between CAR
and OWNER
is not important to your system! At first this seems a little bit counterintuitive, but think about this: Does your boss care who actually owns a car? No! What they care about is who (PERSON) signed a contract to pay to have which CAR parked in his garage. Therefore the relationships that are actually important are between CONTRACT and CAR, and CONTRACT and OWNER. The relationship between CAR and OWNER is not directly significant to your system, unless you have a business rule somewhere that says something about how contracts stay with cars, not owners when people sell their cars. That is probably dicey from a legal perspective.
I think what you're missing is a car_configuration
table. This will have an FK to the cars
table and have car_config_parts
and car_config_tunings
as children, like so:
create table car_configuration (
config_id integer primary key,
car_id integer references cars (car_id)
);
create table car_config_parts (
config_id integer references car_configuration (config_id),
part_id integer references parts (part_id),
constraint car_config_part_pk primary key (config_id ,part_id)
);
create table car_config_tunings (
config_id integer references car_configuration (config_id),
tuning_id integer references tuning (tuning_id),
constraint car_config_tuning_pk primary key (config_id, tuning_id)
);
You can then include the config_id
as a reference in the timeset
table (with no reference to cars
). You'll need to ensure that you can't change the parts and tunings for a configuration or implement some form of versioning on this table to ensure you can reconstruct the exact details used to set a given time in the past.
Best Answer
The cleanest solution is to remove the redundant
number_of_cars
column completely. Your solution (as well as many related ideas floating around) are not safe against concurrent write access.Instead, create a
VIEW
(or aMATERIALIZED VIEW
to optimize read performance) like:Or you could have a custom materialized view where you only update persons that had actual changes. Related example:
If you insist on your original idea (and concurrent write access is not an issue), you could use a trigger solution. Basic example:
You need to cover all possible changes:
INSERT
,UPDATE
,DELETE
on either table. @bgiles added more considerations.