Changes between Initial Version and Version 1 of Normalization_v01


Ignore:
Timestamp:
08/27/26 23:53:41 (5 days ago)
Author:
181201
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization_v01

    v1 v1  
     1= Normalization =
     2
     3== Initial de-normalized relation and functional dependencies ==
     4
     5=== Global set of attributes ===
     6Single unified de-normalized relation that includes all attributes from the ER model. It is important that there are no duplicate attribute names.
     7
     8'''R = {'''
     9user_id, username, first_name, last_name, password, email,
     10
     11admin_id,
     12
     13owner_id,
     14
     15sitter_id,
     16
     17pettype_id, species, average_lifespan, needs_outdoor_walk,
     18
     19pet_id, pet_name, photo, age, special_needs, pet_description,
     20
     21service_id, service_type, service_description,
     22
     23booking_id, booking_status, date_from, date_to, address,
     24
     25review_id, rating, comment,
     26
     27payment_id, amount, payment_type
     28
     29'''}'''
     30
     31=== Functional dependencies ===
     32
     33'''FD1:''' {{{user_id}}} → {{{username}}}, {{{first_name}}}, {{{last_name}}}, {{{password}}}, {{{email}}}
     34
     35'''FD2:''' {{{admin_id}}} → {{{user_id}}}
     36
     37'''FD3:''' {{{owner_id}}} → {{{user_id}}}
     38
     39'''FD4:''' {{{sitter_id}}} → {{{user_id}}}
     40
     41'''FD5:''' {{{pettype_id}}} → {{{species}}}, {{{average_lifespan}}}, {{{needs_outdoor_walk}}}
     42
     43'''FD6:''' {{{pet_id}}} → {{{pet_name}}}, {{{photo}}}, {{{age}}}, {{{special_needs}}}, {{{pet_description}}}, {{{owner_id}}}, {{{pettype_id}}}
     44
     45'''FD7:''' {{{service_id}}} → {{{service_type}}}, {{{service_description}}}
     46
     47'''FD8:''' {{{booking_id}}} → {{{booking_status}}}, {{{date_from}}}, {{{date_to}}}, {{{address}}}, {{{owner_id}}}, {{{sitter_id}}}
     48
     49'''FD9:''' {{{review_id}}} → {{{rating}}}, {{{comment}}}, {{{booking_id}}}
     50
     51'''FD10:''' {{{payment_id}}} → {{{amount}}}, {{{payment_type}}}, {{{booking_id}}}
     52
     53'''FD11:''' ({{{admin_id}}}, {{{user_id}}}) → ∅ (represents AdminManagement M:N)
     54
     55'''FD12:''' ({{{booking_id}}}, {{{pet_id}}}) → ∅ (represents BookingPets M:N)
     56
     57'''FD13:''' ({{{sitter_id}}}, {{{service_id}}}) → ∅ (represents SitterServices M:N)
     58
     59'''FD14:''' ({{{booking_id}}}, {{{service_id}}}) → ∅ (represents BookingServices M:N)
     60
     61== Candidate keys and primary key selection ==
     62
     63=== Determination of Candidate Keys ===
     64To find a candidate key, we must find a minimal set of attributes whose closure contains all attributes of the relation. We begin by classifying all attributes based on where they appear in the Functional Dependencies.
     65
     66=== Attribute Classification (Left / Right Side) ===
     67|| '''Attribute''' || '''Left Side''' || '''Right Side''' || '''Classification''' ||
     68|| '''admin_id''' || ✓ (FD2, FD11) || ✗ || '''Left only''' ||
     69|| '''pet_id''' || ✓ (FD6, FD12) || ✗ || '''Left only''' ||
     70|| '''service_id''' || ✓ (FD7, FD13, FD14) || ✗ || '''Left only''' ||
     71|| '''review_id''' || ✓ (FD9) || ✗ || '''Left only''' ||
     72|| '''payment_id''' || ✓ (FD10) || ✗ || '''Left only''' ||
     73|| {{{user_id}}} || ✓ (FD1, FD11) || ✓ (FD2, FD3, FD4) || Both ||
     74|| {{{owner_id}}} || ✓ (FD3) || ✓ (FD6, FD8) || Both ||
     75|| {{{sitter_id}}} || ✓ (FD4, FD13) || ✓ (FD8) || Both ||
     76|| {{{pettype_id}}} || ✓ (FD5) || ✓ (FD6) || Both ||
     77|| {{{booking_id}}} || ✓ (FD8, FD12, FD14) || ✓ (FD9, FD10) || Both ||
     78|| {{{username}}}, {{{first_name}}}, {{{last_name}}}, {{{password}}}, {{{email}}} || ✗ || ✓ (FD1) || Right only ||
     79|| {{{species}}}, {{{average_lifespan}}}, {{{needs_outdoor_walk}}} || ✗ || ✓ (FD5) || Right only ||
     80|| {{{pet_name}}}, {{{photo}}}, {{{age}}}, {{{special_needs}}}, {{{pet_description}}} || ✗ || ✓ (FD6) || Right only ||
     81|| {{{service_type}}}, {{{service_description}}} || ✗ || ✓ (FD7) || Right only ||
     82|| {{{booking_status}}}, {{{date_from}}}, {{{date_to}}}, {{{address}}} || ✗ || ✓ (FD8) || Right only ||
     83|| {{{rating}}}, {{{comment}}} || ✗ || ✓ (FD9) || Right only ||
     84|| {{{amount}}}, {{{payment_type}}} || ✗ || ✓ (FD10) || Right only ||
     85
     86=== Attributes That Appear ONLY on the Left Side ===
     87According to relational theory, attributes that appear ''only'' on the left side of functional dependencies can never be derived from any other attribute. Therefore, they '''must''' be part of every candidate key:
     88 * '''admin_id'''
     89 * '''pet_id'''
     90 * '''service_id'''
     91 * '''review_id'''
     92 * '''payment_id'''
     93
     94=== Closure Computation ===
     95'''Step 1:''' We start with our mandatory attributes {{{ {admin_id, pet_id, service_id, review_id, payment_id} }}} and compute the mathematical closure:
     96
     97{{{ {admin_id, pet_id, service_id, review_id, payment_id}⁺ }}}:
     98 * '''From FD2''' ({{{admin_id}}} → {{{user_id}}}): We obtain {{{user_id}}}
     99 * '''From FD1''' ({{{user_id}}} → {{{username}}}, {{{first_name}}}...): We obtain {{{username, first_name, last_name, password, email}}}
     100 * '''From FD6''' ({{{pet_id}}} → {{{pet_name}}}, {{{photo}}}... {{{owner_id}}}, {{{pettype_id}}}): We obtain {{{pet_name, photo, age, special_needs, pet_description, owner_id, pettype_id}}}
     101 * '''From FD5''' ({{{pettype_id}}} → {{{species}}}...): We obtain {{{species, average_lifespan, needs_outdoor_walk}}}
     102 * '''From FD7''' ({{{service_id}}} → {{{service_type}}}...): We obtain {{{service_type, service_description}}}
     103 * '''From FD9''' ({{{review_id}}} → {{{rating}}}, {{{comment}}}, {{{booking_id}}}): We obtain {{{rating, comment, booking_id}}}
     104 * '''From FD8''' ({{{booking_id}}} → {{{booking_status}}}... {{{sitter_id}}}): We obtain {{{booking_status, date_from, date_to, address, sitter_id}}}
     105 * '''From FD10''' ({{{payment_id}}} → {{{amount}}}, {{{payment_type}}}, {{{booking_id}}}): We obtain {{{amount, payment_type}}} ({{{booking_id}}} is already in closure)
     106 * '''From FD3 & FD4:''' {{{owner_id}}} and {{{sitter_id}}} map to {{{user_id}}}, which is already in the closure.
     107 * '''From FD11-FD14:''' All composite pairings (e.g., {{{booking_id}}} and {{{pet_id}}}) are already present in the closure, satisfying the M:N relations.
     108
     109'''Closure = Universal_Relation ✓''' (all 33 attributes are successfully derived)
     110
     111=== Minimality Check ===
     112To formally prove this key is minimal, we test proper subsets of '''K = {admin_id, pet_id, service_id, review_id, payment_id}''':
     113
     114|| '''Subset''' || '''Closure Equals Universal_Relation?''' || '''Justification''' ||
     115|| '''K − {admin_id}''' || ✗ NO || Cannot derive {{{admin_id}}}. ||
     116|| '''K − {pet_id}''' || ✗ NO || Cannot derive pet attributes ({{{pet_name, photo, age, special_needs, pet_description}}}). ||
     117|| '''K − {service_id}''' || ✗ NO || Cannot derive service attributes ({{{service_type, service_description}}}). ||
     118|| '''K − {review_id}''' || ✗ NO || Cannot derive review attributes ({{{review_id, rating, comment}}}). ||
     119|| '''K − {payment_id}''' || ✗ NO || Cannot derive payment attributes ({{{payment_id, amount, payment_type}}}). ||
     120
     121'''Conclusion:''' K = {admin_id, pet_id, service_id, review_id, payment_id} is minimal and is the strictly mathematically correct candidate key.
     122
     123=== Choice of Primary Key ===
     124'''Chosen Primary Key:''' {{{ {admin_id, pet_id, service_id, review_id, payment_id} }}}
     125
     126'''Justification:''' This composite key is the officially proven minimal Candidate Key. Attempting to include other logical identifiers (such as {{{owner_id}}}, {{{sitter_id}}}, or {{{booking_id}}}) would violate the rule of minimality, because the closure proof demonstrates those attributes are functionally dependent on the core transactional IDs.
     127
     128=== Current Normal Form Status ===
     129Before decomposition, the universal relation '''R''' is in '''1NF'''. It satisfies 1NF because all attributes contain atomic values and there are no repeating groups. However, it violates 2NF due to severe partial dependencies on the composite primary key.
     130
     131== Step-by-step decomposition to highest possible normal form ==
     132
     133=== 1. Decomposition to 2NF ===
     134
     135'''Relation analyzed:''' The universal de-normalized relation '''R'''.
     136
     137'''Issues with higher normal forms:''' R violates 2NF because non-prime attributes are partially dependent on components of the composite primary key. For example, {{{pet_name}}} depends ONLY on {{{pet_id}}}, not on the entire composite key '''K'''.
     138
     139'''Action taken:''' We decompose R into smaller relations by grouping attributes based on their exact determinants (eliminating partial dependencies).
     140
     141'''Relations obtained after 2NF decomposition:'''
     142
     143'''Users''' ({{{user_id}}}, {{{username}}}, {{{first_name}}}, {{{last_name}}}, {{{password}}}, {{{email}}})
     144
     145'''Admins''' ({{{admin_id}}}, {{{user_id}}})
     146
     147'''PetOwners''' ({{{owner_id}}}, {{{user_id}}})
     148
     149'''PetSitters''' ({{{sitter_id}}}, {{{user_id}}})
     150
     151'''PetTypes''' ({{{pettype_id}}}, {{{species}}}, {{{average_lifespan}}}, {{{needs_outdoor_walk}}})
     152
     153'''Pets''' ({{{pet_id}}}, {{{pet_name}}}, {{{photo}}}, {{{age}}}, {{{special_needs}}}, {{{pet_description}}}, {{{owner_id}}}, {{{pettype_id}}})
     154
     155'''Services''' ({{{service_id}}}, {{{service_type}}}, {{{service_description}}})
     156
     157'''Bookings''' ({{{booking_id}}}, {{{booking_status}}}, {{{date_from}}}, {{{date_to}}}, {{{address}}}, {{{owner_id}}}, {{{sitter_id}}})
     158
     159'''Reviews''' ({{{review_id}}}, {{{rating}}}, {{{comment}}}, {{{booking_id}}})
     160
     161'''Payments''' ({{{payment_id}}}, {{{amount}}}, {{{payment_type}}}, {{{booking_id}}})
     162
     163'''AdminManagement''' ({{{admin_id}}}, {{{user_id}}})
     164
     165'''BookingPets''' ({{{booking_id}}}, {{{pet_id}}})
     166
     167'''SitterServices''' ({{{sitter_id}}}, {{{service_id}}})
     168
     169'''BookingServices''' ({{{booking_id}}}, {{{service_id}}})
     170
     171'''1. Loss-less Join Property Validation:'''
     172By definition (Heath's Theorem), a decomposition of relation ''R'' into ''R1'' and ''R2'' is lossless if the intersection of their attributes (''R1'' ∩ ''R2'') forms a superkey for either ''R1'' or ''R2''. To achieve our final schema without data loss, the universal relation ''R'' was decomposed through '''13 successive binary splits'''. Below is the formal proof of each split, detailing the exact attributes partitioned.
     173
     174Let '''R_remainder''' be the remainder relation after each split
     175
     176'''Initial State:'''
     177''R'' = {{{ {user_id, username, first_name, last_name, password, email, admin_id, owner_id, sitter_id, pettype_id, species, average_lifespan, needs_outdoor_walk, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     178
     179'''Split 1: Extracting Users (FD1)'''
     180 * '''Decomposition:''' ''R'' is split into '''Users''' and '''R_remainder1'''.
     181 * '''Attributes in Users:''' {{{ {user_id, username, first_name, last_name, password, email} }}}
     182 * '''Attributes in R_remainder1:''' {{{ {user_id, admin_id, owner_id, sitter_id, pettype_id, species, average_lifespan, needs_outdoor_walk, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     183 * '''Intersection:''' '''Users''' ∩ '''R_remainder1''' = {{{ {user_id} }}}
     184 * '''Proof:''' {{{user_id}}} is the Primary Key of the '''Users''' table. The split is lossless.
     185
     186'''Split 2: Extracting Admins (FD2)'''
     187 * '''Decomposition:''' '''R_remainder1''' is split into '''Admins''' and '''R_remainder2'''.
     188 * '''Attributes in Admins:''' {{{ {admin_id, user_id} }}}
     189 * '''Attributes in R_remainder2:''' {{{ {admin_id, owner_id, sitter_id, pettype_id, species, average_lifespan, needs_outdoor_walk, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     190 * '''Intersection:''' '''Admins''' ∩ '''R_remainder2''' = {{{ {admin_id} }}}
     191 * '''Proof:''' {{{admin_id}}} is the Primary Key of the '''Admins''' table. The split is lossless.
     192
     193'''Split 3: Extracting Pet Owners (FD3)'''
     194 * '''Decomposition:''' '''R_remainder2''' is split into '''PetOwners''' and '''R_remainder3'''.
     195 * '''Attributes in PetOwners:''' {{{ {owner_id, user_id} }}}
     196 * '''Attributes in R_remainder3:''' {{{ {admin_id, owner_id, sitter_id, pettype_id, species, average_lifespan, needs_outdoor_walk, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     197 * '''Intersection:''' '''PetOwners''' ∩ '''R_remainder3''' = {{{ {owner_id} }}}
     198 * '''Proof:''' {{{owner_id}}} is the Primary Key of the '''PetOwners''' table. The split is lossless.
     199
     200'''Split 4: Extracting Pet Sitters (FD4)'''
     201 * '''Decomposition:''' '''R_remainder3''' is split into '''PetSitters''' and '''R_remainder4'''.
     202 * '''Attributes in PetSitters:''' {{{ {sitter_id, user_id} }}}
     203 * '''Attributes in R_remainder4:''' {{{ {admin_id, owner_id, sitter_id, pettype_id, species, average_lifespan, needs_outdoor_walk, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     204 * '''Intersection:''' '''PetSitters''' ∩ '''R_remainder4''' = {{{ {sitter_id} }}}
     205 * '''Proof:''' {{{sitter_id}}} is the Primary Key of the '''PetSitters''' table. The split is lossless.
     206
     207'''Split 5: Extracting Pet Types (FD5)'''
     208 * '''Decomposition:''' '''R_remainder4''' is split into '''PetTypes''' and '''R_remainder5'''.
     209 * '''Attributes in PetTypes:''' {{{ {pettype_id, species, average_lifespan, needs_outdoor_walk} }}}
     210 * '''Attributes in R_remainder5:''' {{{ {admin_id, owner_id, sitter_id, pettype_id, pet_id, pet_name, photo, age, special_needs, pet_description, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     211 * '''Intersection:''' '''PetTypes''' ∩ '''R_remainder5''' = {{{ {pettype_id} }}}
     212 * '''Proof:''' {{{pettype_id}}} is the Primary Key of the '''PetTypes''' table. The split is lossless.
     213
     214'''Split 6: Extracting Pets (FD6)'''
     215 * '''Decomposition:''' '''R_remainder5''' is split into '''Pets''' and '''R_remainder6'''.
     216 * '''Attributes in Pets:''' {{{ {pet_id, pet_name, photo, age, special_needs, pet_description, owner_id, pettype_id} }}}
     217 * '''Attributes in R_remainder6:''' {{{ {admin_id, owner_id, sitter_id, pet_id, service_id, service_type, service_description, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     218 * '''Intersection:''' '''Pets''' ∩ '''R_remainder6''' = {{{ {pet_id} }}}
     219 * '''Proof:''' {{{pet_id}}} is the Primary Key of the '''Pets''' table. The split is lossless.
     220
     221'''Split 7: Extracting Services (FD7)'''
     222 * '''Decomposition:''' '''R_remainder6''' is split into '''Services''' and '''R_remainder7'''.
     223 * '''Attributes in Services:''' {{{ {service_id, service_type, service_description} }}}
     224 * '''Attributes in R_remainder7:''' {{{ {admin_id, owner_id, sitter_id, pet_id, service_id, booking_id, booking_status, date_from, date_to, address, review_id, rating, comment, payment_id, amount, payment_type} }}}
     225 * '''Intersection:''' '''Services''' ∩ '''R_remainder7''' = {{{ {service_id} }}}
     226 * '''Proof:''' {{{service_id}}} is the Primary Key of the '''Services''' table. The split is lossless.
     227
     228'''Split 8: Extracting Bookings (FD8)'''
     229 * '''Decomposition:''' '''R_remainder7''' is split into '''Bookings''' and '''R_remainder8'''.
     230 * '''Attributes in Bookings:''' {{{ {booking_id, booking_status, date_from, date_to, address, owner_id, sitter_id} }}}
     231 * '''Attributes in R_remainder8:''' {{{ {admin_id, sitter_id, pet_id, service_id, booking_id, review_id, rating, comment, payment_id, amount, payment_type} }}}
     232 * '''Intersection:''' '''Bookings''' ∩ '''R_remainder8''' = {{{ {booking_id} }}}
     233 * '''Proof:''' {{{booking_id}}} is the Primary Key of the '''Bookings''' table. The split is lossless.
     234
     235'''Split 9: Extracting Reviews (FD9)'''
     236 * '''Decomposition:''' '''R_remainder8''' is split into '''Reviews''' and '''R_remainder9'''.
     237 * '''Attributes in Reviews:''' {{{ {review_id, rating, comment, booking_id} }}}
     238 * '''Attributes in R_remainder9:''' {{{ {admin_id, sitter_id, pet_id, service_id, booking_id, payment_id, amount, payment_type} }}}
     239 * '''Intersection:''' '''Reviews''' ∩ '''R_remainder9''' = {{{ {review_id} }}}
     240 * '''Proof:''' {{{review_id}}} is the Primary Key of the '''Reviews''' table. The split is lossless.
     241
     242'''Split 10: Extracting Payments (FD10)'''
     243 * '''Decomposition:''' '''R_remainder9''' is split into '''Payments''' and '''R_remainder10'''.
     244 * '''Attributes in Payments:''' {{{ {payment_id, amount, payment_type, booking_id} }}}
     245 * '''Attributes in R_remainder10:''' {{{ {admin_id, sitter_id, pet_id, service_id, booking_id} }}}
     246 * '''Intersection:''' '''Payments''' ∩ '''R_remainder10''' = {{{ {payment_id} }}}
     247 * '''Proof:''' {{{payment_id}}} is the Primary Key of the '''Payments''' table. The split is lossless.
     248
     249'''Splits 11-13: Extracting M:N Relations/Junctions (FD11-FD14)'''
     250The final remainder relation ('''R_remainder10''') contains only the composite keys representing the Many-to-Many relationships:
     251 * '''AdminManagement:''' {{{ {admin_id, user_id} }}}
     252 * '''BookingPets:''' {{{ {booking_id, pet_id} }}}
     253 * '''SitterServices:''' {{{ {sitter_id, service_id} }}}
     254 * '''BookingServices:''' {{{ {booking_id, service_id} }}}
     255
     256Because these final tables consist only of their composite primary keys, any further binary separation will trivially satisfy Heath's Theorem.
     257
     258'''Conclusion:''' Because every single step of the decomposition shared an intersection that was a guaranteed Primary Key, the final 14-table schema is strictly lossless.
     259
     260'''2. Dependency Preservation:'''
     261A decomposition is dependency preserving if the union of the functional dependencies in the new tables is equivalent to the original set of FDs (FD1 to FD14).
     262Because we explicitly created our relations based on the exact determinants of our FDs, every single functional dependency is fully localized within a single table.
     263 * For example, FD5 ({{{pettype_id → species, average_lifespan, needs_outdoor_walk}}}) can be completely verified within the new '''PetTypes''' table without needing to perform a JOIN operation with any other table.
     264 * Similarly, FD7 ({{{service_id → service_type, service_description}}}) is entirely contained within the '''Services''' table.
     265Since all 14 original FDs are preserved natively inside the 14 new relations, the decomposition is strictly dependency preserving.
     266
     267=== Step 2: Decomposition to 3NF ===
     268
     269'''Relations analyzed:''' All 14 relations obtained from the 2NF decomposition.
     270
     271'''Issues with higher normal forms:''' A relation violates 3NF if there is a transitive dependency (A → B → C) where a non-prime attribute determines another non-prime attribute.
     272
     273'''Action taken:''' We inspect the 2NF relations to ensure that all non-key attributes depend ''only'' on the primary key, and not on any other non-key attributes. We specifically target tables containing Foreign Keys, as this is where transitive chains can be present.
     274
     275* '''In Bookings:''' While {{{booking_id}}} determines {{{owner_id}}}, we must check if {{{owner_id}}} (a non-prime attribute in this table) determines any other non-prime attributes ''within'' this table. It does not. The descriptive user details for the owner are safely isolated in the '''Users''' table.
     276* '''In Reviews:''' While {{{review_id}}} determines {{{booking_id}}}, we must check if {{{booking_id}}} (a non-prime attribute in this table) determines any other non-prime attributes ''within'' this table (such as the sitter's details). It does not. Those details are isolated in their respective tables.
     277* '''In Base Entities (Users, PetTypes, Services):''' All non-prime attributes logically depend directly on the primary key (example {{{species}}} depends only on {{{pettype_id}}}), making transitive chains mathematically impossible.
     278* '''In Junction Tables (BookingPets, AdminManagement):''' These relations consist purely of composite primary keys with zero non-prime attributes, automatically satisfying 3NF.
     279
     280'''Result:''' Because we did not store redundant, descriptive data alongside our foreign keys, there are no instances where a non-prime attribute determines another non-prime attribute within the same relation.
     281
     282'''Status:''' All 14 relations naturally satisfy '''3NF'''.
     283
     284=== 3. Decomposition to BCNF ===
     285
     286'''Relations analyzed:''' All 14 relations currently in 3NF.
     287
     288'''Issues with higher normal forms:''' A relation violates Boyce-Codd Normal Form (BCNF) if a non-trivial functional dependency X → Y exists where X is not a superkey.
     289
     290'''Action taken:''' We evaluate the left side (determinant) of every functional dependency within all 14 relations:
     291
     292In '''Users''', {{{user_id}}} is a superkey.
     293
     294In '''Admins''', {{{admin_id}}} is a superkey.
     295
     296In '''PetOwners''', {{{owner_id}}} is a superkey.
     297
     298In '''PetSitters''', {{{sitter_id}}} is a superkey.
     299
     300In '''PetTypes''', {{{pettype_id}}} is a superkey.
     301
     302In '''Pets''', {{{pet_id}}} is a superkey.
     303
     304In '''Services''', {{{service_id}}} is a superkey.
     305
     306In '''Bookings''', {{{booking_id}}} is a superkey.
     307
     308In '''Reviews''', {{{review_id}}} is a superkey.
     309
     310In '''Payments''', {{{payment_id}}} is a superkey.
     311
     312In '''AdminManagement''', the composite key ({{{admin_id}}}, {{{user_id}}}) is the only determinant, meaning it is trivially a superkey.
     313
     314In '''BookingPets''', the composite key ({{{booking_id}}}, {{{pet_id}}}) is the only determinant, meaning it is trivially a superkey.
     315
     316In '''SitterServices''', the composite key ({{{sitter_id}}}, {{{service_id}}}) is the only determinant, meaning it is trivially a superkey.
     317
     318In '''BookingServices''', the composite key ({{{booking_id}}}, {{{service_id}}}) is the only determinant, meaning it is trivially a superkey.
     319
     320'''Result:''' In every single relation, the determinant is a candidate/superkey.
     321
     322'''Status:''' All 14 relations naturally satisfy '''BCNF'''. The decomposition process is complete.
     323
     324== Final result and discussion ==
     325
     326=== Final normalized relational design ===
     327The final database schema operates in strict BCNF with the following 14 relations:
     328
     329'''Users''' ({{{user_id}}}, {{{username}}}, {{{first_name}}}, {{{last_name}}}, {{{password}}}, {{{email}}})
     330
     331'''Admins''' ({{{admin_id}}}, {{{user_id}}})
     332
     333'''PetOwners''' ({{{owner_id}}}, {{{user_id}}})
     334
     335'''PetSitters''' ({{{sitter_id}}}, {{{user_id}}})
     336
     337'''PetTypes''' ({{{pettype_id}}}, {{{species}}}, {{{average_lifespan}}}, {{{needs_outdoor_walk}}})
     338
     339'''Pets''' ({{{pet_id}}}, {{{pet_name}}}, {{{photo}}}, {{{age}}}, {{{special_needs}}}, {{{pet_description}}}, {{{owner_id}}}, {{{pettype_id}}})
     340
     341'''Services''' ({{{service_id}}}, {{{service_type}}}, {{{service_description}}})
     342
     343'''Bookings''' ({{{booking_id}}}, {{{booking_status}}}, {{{date_from}}}, {{{date_to}}}, {{{address}}}, {{{owner_id}}}, {{{sitter_id}}})
     344
     345'''Reviews''' ({{{review_id}}}, {{{rating}}}, {{{comment}}}, {{{booking_id}}})
     346
     347'''Payments''' ({{{payment_id}}}, {{{amount}}}, {{{payment_type}}}, {{{booking_id}}})
     348
     349'''AdminManagement''' ({{{admin_id}}}, {{{user_id}}})
     350
     351'''BookingPets''' ({{{booking_id}}}, {{{pet_id}}})
     352
     353'''SitterServices''' ({{{sitter_id}}}, {{{service_id}}})
     354
     355'''BookingServices''' ({{{booking_id}}}, {{{service_id}}})
     356
     357=== Discussion - compare with Phase 2 ===
     358With completing the normalization process up to BCNF, we have proven that the resulting schema is identical to the logical design created in Phase 2.