Changes between Initial Version and Version 1 of Normalization


Ignore:
Timestamp:
04/05/26 19:08:06 (6 days ago)
Author:
221511
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v1 v1  
     1= Normalization =
     2
     3== De-normalized Database Form ==
     4
     5The normalization process starts from a single universal relation '''U''' that contains all attributes from the ER model, as if all data resided in one table. Attribute names are made globally unique by prefixing where necessary.
     6
     7{{{
     8U ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     9    user_id, first_name, last_name, email, password, user_type_id, user_type_name, user_type_description,
     10    approved_by,
     11    resource_id, resource_name, resource_description, available_from, available_to, available_weekends,
     12    resource_type_id, resource_type_name, is_physical,
     13    location_id, building, room )
     14}}}
     15
     16The relation has 27 attributes total, representing reservation data, user data, resource data, and their associated types and locations.
     17
     18== Functional Dependencies ==
     19
     20=== Initial Set of Functional Dependencies ===
     21
     22The following functional dependencies are derived from the semantics of the domain:
     23
     24||'''ID'''||'''Functional Dependency'''||'''Source'''||
     25||FD1||user_type_id -> user_type_name, user_type_description||!UserType entity; type_id uniquely identifies each user type||
     26||FD2||user_type_name -> user_type_id, user_type_description||!UserType entity; type_name is also unique (UNIQUE constraint)||
     27||FD3||user_id -> first_name, last_name, email, password, user_type_id||User entity; user_id uniquely identifies each user||
     28||FD4||email -> user_id, first_name, last_name, password, user_type_id||User entity; email is also unique (UNIQUE constraint)||
     29||FD5||resource_type_id -> resource_type_name, is_physical||!ResourceType entity; type_id uniquely identifies each resource type||
     30||FD6||resource_type_name -> resource_type_id, is_physical||!ResourceType entity; type_name is also unique (UNIQUE constraint)||
     31||FD7||location_id -> building, room||Location entity; location_id uniquely identifies each location||
     32||FD8||{building, room} -> location_id||Location entity; building+room combination is unique (composite UNIQUE constraint)||
     33||FD9||resource_id -> resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id||Resource entity; resource_id uniquely identifies each resource||
     34||FD10||reservation_id -> start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id||Reservation entity; reservation_id uniquely identifies each reservation||
     35
     36=== Canonical Cover ===
     37
     38To obtain the canonical cover, we apply the following reductions:
     39
     40 1. '''Reduce FD2:''' Since user_type_name -> user_type_id (FD2) and user_type_id -> user_type_description (FD1), the attribute user_type_description is derivable by transitivity. Reduced to: '''user_type_name -> user_type_id'''
     41
     42 2. '''Reduce FD4:''' Since email -> user_id (FD4) and user_id -> first_name, last_name, password, user_type_id (FD3), all attributes except user_id are derivable by transitivity. Reduced to: '''email -> user_id'''
     43
     44 3. '''Reduce FD6:''' Since resource_type_name -> resource_type_id (FD6) and resource_type_id -> is_physical (FD5), the attribute is_physical is derivable by transitivity. Reduced to: '''resource_type_name -> resource_type_id'''
     45
     46No further reductions are possible (no extraneous left-hand-side attributes, no redundant FDs).
     47
     48'''Canonical Cover F,,c,,:'''
     49
     50||'''ID'''||'''Functional Dependency'''||
     51||FD1||user_type_id -> user_type_name, user_type_description||
     52||FD2'||user_type_name -> user_type_id||
     53||FD3||user_id -> first_name, last_name, email, password, user_type_id||
     54||FD4'||email -> user_id||
     55||FD5||resource_type_id -> resource_type_name, is_physical||
     56||FD6'||resource_type_name -> resource_type_id||
     57||FD7||location_id -> building, room||
     58||FD8||{building, room} -> location_id||
     59||FD9||resource_id -> resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id||
     60||FD10||reservation_id -> start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id||
     61
     62== Candidate Keys and Primary Key ==
     63
     64To find candidate keys of U, we compute attribute closures.
     65
     66=== Attribute Classification (Left / Right Side) ===
     67
     68||'''Attribute'''||'''Left Side'''||'''Right Side'''||'''Classification'''||
     69||reservation_id||Yes (FD10)||No||'''Left only'''||
     70||start_time||No||Yes (FD10)||Right only||
     71||end_time||No||Yes (FD10)||Right only||
     72||status||No||Yes (FD10)||Right only||
     73||purpose||No||Yes (FD10)||Right only||
     74||created_at||No||Yes (FD10)||Right only||
     75||recurrence_group_id||No||Yes (FD10)||Right only||
     76||user_id||Yes (FD3)||Yes (FD4', FD10)||Both||
     77||first_name||No||Yes (FD3)||Right only||
     78||last_name||No||Yes (FD3)||Right only||
     79||email||Yes (FD4')||Yes (FD3)||Both||
     80||password||No||Yes (FD3)||Right only||
     81||user_type_id||Yes (FD1)||Yes (FD2', FD3)||Both||
     82||user_type_name||Yes (FD2')||Yes (FD1)||Both||
     83||user_type_description||No||Yes (FD1)||Right only||
     84||approved_by||No||Yes (FD10)||Right only||
     85||resource_id||Yes (FD9)||Yes (FD10)||Both||
     86||resource_name||No||Yes (FD9)||Right only||
     87||resource_description||No||Yes (FD9)||Right only||
     88||available_from||No||Yes (FD9)||Right only||
     89||available_to||No||Yes (FD9)||Right only||
     90||available_weekends||No||Yes (FD9)||Right only||
     91||resource_type_id||Yes (FD5)||Yes (FD6', FD9)||Both||
     92||resource_type_name||Yes (FD6')||Yes (FD5)||Both||
     93||is_physical||No||Yes (FD5)||Right only||
     94||location_id||Yes (FD7)||Yes (FD8, FD9)||Both||
     95||building||Yes (FD8)||Yes (FD7)||Both||
     96||room||Yes (FD8)||Yes (FD7)||Both||
     97
     98'''Attributes appearing ONLY on the left side:''' reservation_id
     99
     100This attribute must be part of every candidate key.
     101
     102=== Closure Computation ===
     103
     104{{{
     105{reservation_id}+
     106  = {reservation_id}
     107  apply FD10: + {start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id}
     108  apply FD3:  + {first_name, last_name, email, password, user_type_id}
     109  apply FD1:  + {user_type_name, user_type_description}
     110  apply FD9:  + {resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id}
     111  apply FD5:  + {resource_type_name, is_physical}
     112  apply FD7:  + {building, room}
     113  = U (all 27 attributes)
     114}}}
     115
     116Since {reservation_id}^+^ = U, '''reservation_id''' is a superkey. It is a single attribute, so it is minimal, therefore it is a '''candidate key'''.
     117
     118Since reservation_id is the only attribute appearing exclusively on the left side of all FDs, and its closure already covers U, no other minimal set of attributes can form a candidate key. Therefore, '''{reservation_id} is the only candidate key'''.
     119
     120'''Primary key selected:''' reservation_id
     121
     122'''Prime attribute:''' reservation_id [[BR]]
     123'''Non-prime attributes:''' all remaining 26 attributes
     124
     125== 1NF Decomposition ==
     126
     127For a relation to be in 1NF, all attribute values must be atomic (no repeating groups, no multi-valued attributes).
     128
     129'''Check:''' All 27 attributes of U have atomic domains:
     130 * VARCHAR for text attributes (first_name, last_name, email, etc.)
     131 * INTEGER for identifiers (user_id, resource_id, etc.)
     132 * BOOLEAN for flags (is_physical, available_weekends)
     133 * TIMESTAMP for date/time values (start_time, end_time, created_at)
     134 * TIME for daily time values (available_from, available_to)
     135 * UUID for group identifiers (recurrence_group_id)
     136
     137There are no multi-valued or composite attributes. '''U is already in 1NF.''' No decomposition is needed at this stage.
     138
     139== 2NF Decomposition ==
     140
     141For a relation to be in 2NF, it must be in 1NF and have no partial dependencies (no non-prime attribute may depend on a proper subset of a candidate key).
     142
     143'''Check:''' The only candidate key of U is {reservation_id}, which is a single attribute. A single-attribute key has no proper subsets, therefore partial dependencies are impossible by definition.
     144
     145'''U is already in 2NF.''' No decomposition is needed at this stage.
     146
     147== 3NF Decomposition ==
     148
     149For a relation to be in 3NF, it must be in 2NF and for every non-trivial FD X -> A: either X is a superkey, or A is a prime attribute.
     150
     151'''Check:''' The following FDs violate 3NF because their left-hand sides are not superkeys and their right-hand sides contain only non-prime attributes:
     152
     153||'''FD'''||'''Violation'''||'''Transitive Chain'''||
     154||FD1: user_type_id -> user_type_name, user_type_description||user_type_id is not a superkey||reservation_id -> user_id -> user_type_id -> {user_type_name, user_type_description}||
     155||FD3: user_id -> first_name, last_name, email, password, user_type_id||user_id is not a superkey||reservation_id -> user_id -> {first_name, last_name, email, password, user_type_id}||
     156||FD5: resource_type_id -> resource_type_name, is_physical||resource_type_id is not a superkey||reservation_id -> resource_id -> resource_type_id -> {resource_type_name, is_physical}||
     157||FD7: location_id -> building, room||location_id is not a superkey||reservation_id -> resource_id -> location_id -> {building, room}||
     158||FD9: resource_id -> resource_name, ...||resource_id is not a superkey||reservation_id -> resource_id -> {resource_name, ...}||
     159
     160'''U is NOT in 3NF.''' We proceed with step-by-step decomposition, starting from the deepest transitive dependency chains.
     161
     162=== Step 1: Decompose !UserTypes from U ===
     163
     164'''Relation analyzed:''' U (27 attributes, key: {reservation_id})
     165
     166'''FDs that apply:''' FD1, FD2', FD3, FD4', FD5, FD6', FD7, FD8, FD9, FD10
     167
     168'''Violating FD selected:''' FD1: user_type_id -> user_type_name, user_type_description [[BR]]
     169user_type_id is not a superkey of U, and user_type_name, user_type_description are non-prime. This is a transitive dependency: reservation_id -> user_id -> user_type_id -> {user_type_name, user_type_description}.
     170
     171'''Decomposition:'''
     172
     173 * '''R1(user_type_id, user_type_name, user_type_description)'''
     174   * FDs in R1: user_type_id -> user_type_name, user_type_description; user_type_name -> user_type_id
     175   * Candidate keys: {user_type_id}, {user_type_name}
     176   * Primary key: user_type_id
     177   * Normal form: BCNF (all FD determinants are superkeys)
     178
     179 * '''U1''' = U - {user_type_name, user_type_description}, keeping user_type_id
     180{{{
     181U1 ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     182     user_id, first_name, last_name, email, password, user_type_id,
     183     approved_by,
     184     resource_id, resource_name, resource_description, available_from, available_to, available_weekends,
     185     resource_type_id, resource_type_name, is_physical,
     186     location_id, building, room )
     187}}}
     188   * Key of U1: {reservation_id}
     189
     190'''Lossless join check:''' R1 ∩ U1 = {user_type_id}, which is a candidate key of R1. Lossless join preserved. ✓ [[BR]]
     191'''Dependency preservation:''' FD1 and FD2' are preserved in R1; all other FDs remain in U1. ✓
     192
     193=== Step 2: Decompose Users from U1 ===
     194
     195'''Relation analyzed:''' U1 (25 attributes, key: {reservation_id})
     196
     197'''FDs that apply:''' FD3, FD4', FD5, FD6', FD7, FD8, FD9, FD10
     198
     199'''Violating FD selected:''' FD3: user_id -> first_name, last_name, email, password, user_type_id [[BR]]
     200user_id is not a superkey of U1, and all RHS attributes are non-prime. This is a transitive dependency: reservation_id -> user_id -> {first_name, last_name, email, password, user_type_id}.
     201
     202'''Decomposition:'''
     203
     204 * '''R2(user_id, first_name, last_name, email, password, user_type_id)'''
     205   * FDs in R2: user_id -> first_name, last_name, email, password, user_type_id; email -> user_id
     206   * Candidate keys: {user_id}, {email} (since {email}^+^ = {email, user_id, first_name, last_name, password, user_type_id} = R2)
     207   * Primary key: user_id
     208   * Normal form: BCNF (both user_id and email are superkeys)
     209
     210 * '''U2''' = U1 - {first_name, last_name, email, password, user_type_id}, keeping user_id
     211{{{
     212U2 ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     213     user_id, approved_by,
     214     resource_id, resource_name, resource_description, available_from, available_to, available_weekends,
     215     resource_type_id, resource_type_name, is_physical,
     216     location_id, building, room )
     217}}}
     218   * Key of U2: {reservation_id}
     219
     220'''Lossless join check:''' R2 ∩ U2 = {user_id}, which is a candidate key of R2. Lossless join preserved. ✓ [[BR]]
     221'''Dependency preservation:''' FD3 and FD4' are preserved in R2; all other FDs remain in U2. ✓
     222
     223=== Step 3: Decompose !ResourceTypes from U2 ===
     224
     225'''Relation analyzed:''' U2 (20 attributes, key: {reservation_id})
     226
     227'''FDs that apply:''' FD5, FD6', FD7, FD8, FD9, FD10
     228
     229'''Violating FD selected:''' FD5: resource_type_id -> resource_type_name, is_physical [[BR]]
     230resource_type_id is not a superkey of U2. This is a transitive dependency: reservation_id -> resource_id -> resource_type_id -> {resource_type_name, is_physical}.
     231
     232'''Decomposition:'''
     233
     234 * '''R3(resource_type_id, resource_type_name, is_physical)'''
     235   * FDs in R3: resource_type_id -> resource_type_name, is_physical; resource_type_name -> resource_type_id
     236   * Candidate keys: {resource_type_id}, {resource_type_name}
     237   * Primary key: resource_type_id
     238   * Normal form: BCNF (all FD determinants are superkeys)
     239
     240 * '''U3''' = U2 - {resource_type_name, is_physical}, keeping resource_type_id
     241{{{
     242U3 ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     243     user_id, approved_by,
     244     resource_id, resource_name, resource_description, available_from, available_to, available_weekends,
     245     resource_type_id,
     246     location_id, building, room )
     247}}}
     248   * Key of U3: {reservation_id}
     249
     250'''Lossless join check:''' R3 ∩ U3 = {resource_type_id}, which is a candidate key of R3. Lossless join preserved. ✓ [[BR]]
     251'''Dependency preservation:''' FD5 and FD6' are preserved in R3; all other FDs remain in U3. ✓
     252
     253=== Step 4: Decompose Locations from U3 ===
     254
     255'''Relation analyzed:''' U3 (18 attributes, key: {reservation_id})
     256
     257'''FDs that apply:''' FD7, FD8, FD9, FD10
     258
     259'''Violating FD selected:''' FD7: location_id -> building, room [[BR]]
     260location_id is not a superkey of U3. This is a transitive dependency: reservation_id -> resource_id -> location_id -> {building, room}.
     261
     262'''Decomposition:'''
     263
     264 * '''R4(location_id, building, room)'''
     265   * FDs in R4: location_id -> building, room; {building, room} -> location_id
     266   * Candidate keys: {location_id}, {building, room}
     267   * Primary key: location_id
     268   * Normal form: BCNF (all FD determinants are superkeys)
     269
     270 * '''U4''' = U3 - {building, room}, keeping location_id
     271{{{
     272U4 ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     273     user_id, approved_by,
     274     resource_id, resource_name, resource_description, available_from, available_to, available_weekends,
     275     resource_type_id, location_id )
     276}}}
     277   * Key of U4: {reservation_id}
     278
     279'''Lossless join check:''' R4 ∩ U4 = {location_id}, which is a candidate key of R4. Lossless join preserved. ✓ [[BR]]
     280'''Dependency preservation:''' FD7 and FD8 are preserved in R4; all other FDs remain in U4. ✓
     281
     282=== Step 5: Decompose Resources from U4 ===
     283
     284'''Relation analyzed:''' U4 (16 attributes, key: {reservation_id})
     285
     286'''FDs that apply:''' FD9, FD10
     287
     288'''Violating FD selected:''' FD9: resource_id -> resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id [[BR]]
     289resource_id is not a superkey of U4. This is a transitive dependency: reservation_id -> resource_id -> {resource_name, resource_description, ...}.
     290
     291'''Decomposition:'''
     292
     293 * '''R5(resource_id, resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id)'''
     294   * FDs in R5: resource_id -> resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id
     295   * Candidate key: {resource_id}
     296   * Primary key: resource_id
     297   * Normal form: BCNF (the only FD has superkey determinant)
     298
     299 * '''U5''' = U4 - {resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id}, keeping resource_id
     300{{{
     301U5 ( reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id,
     302     user_id, approved_by, resource_id )
     303}}}
     304   * Key of U5: {reservation_id}
     305
     306'''Lossless join check:''' R5 ∩ U5 = {resource_id}, which is a candidate key of R5. Lossless join preserved. ✓ [[BR]]
     307'''Dependency preservation:''' FD9 is preserved in R5; FD10 remains in U5. ✓
     308
     309=== Step 6: Verify U5 (Reservations) ===
     310
     311'''Relation analyzed:''' U5 (10 attributes)
     312
     313'''FDs in U5:''' FD10: reservation_id -> start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id
     314
     315'''Candidate key:''' {reservation_id} [[BR]]
     316'''Primary key:''' reservation_id
     317
     318Every FD in U5 has a superkey (reservation_id) on the left-hand side. There are no transitive dependencies. '''U5 is in 3NF.''' ✓
     319
     320=== 3NF Result ===
     321
     322After decomposition, we have six relations, all in 3NF:
     323
     324||'''Relation'''||'''Attributes'''||'''Candidate Keys'''||'''Primary Key'''||
     325||R1||user_type_id, user_type_name, user_type_description||{user_type_id}, {user_type_name}||user_type_id||
     326||R2||user_id, first_name, last_name, email, password, user_type_id||{user_id}, {email}||user_id||
     327||R3||resource_type_id, resource_type_name, is_physical||{resource_type_id}, {resource_type_name}||resource_type_id||
     328||R4||location_id, building, room||{location_id}, {building, room}||location_id||
     329||R5||resource_id, resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id||{resource_id}||resource_id||
     330||R6||reservation_id, start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id||{reservation_id}||reservation_id||
     331
     332'''All functional dependencies from F,,c,, are preserved:'''
     333||'''FD'''||'''Preserved in'''||
     334||FD1: user_type_id -> user_type_name, user_type_description||R1||
     335||FD2': user_type_name -> user_type_id||R1||
     336||FD3: user_id -> first_name, last_name, email, password, user_type_id||R2||
     337||FD4': email -> user_id||R2||
     338||FD5: resource_type_id -> resource_type_name, is_physical||R3||
     339||FD6': resource_type_name -> resource_type_id||R3||
     340||FD7: location_id -> building, room||R4||
     341||FD8: {building, room} -> location_id||R4||
     342||FD9: resource_id -> resource_name, ...||R5||
     343||FD10: reservation_id -> start_time, ...||R6||
     344
     345== BCNF Verification ==
     346
     347A relation is in BCNF if for every non-trivial FD X -> A, X is a superkey. We verify each relation from the 3NF result.
     348
     349=== R1 (!UserTypes) ===
     350
     351'''FDs:''' user_type_id -> user_type_name, user_type_description; user_type_name -> user_type_id [[BR]]
     352'''Candidate keys:''' {user_type_id}, {user_type_name}
     353
     354||'''FD'''||'''Determinant'''||'''Superkey?'''||
     355||user_type_id -> user_type_name, user_type_description||user_type_id||Yes||
     356||user_type_name -> user_type_id||user_type_name||Yes||
     357
     358'''R1 is in BCNF.''' ✓
     359
     360=== R2 (Users) ===
     361
     362'''FDs:''' user_id -> first_name, last_name, email, password, user_type_id; email -> user_id [[BR]]
     363'''Candidate keys:''' {user_id}, {email} (verified: {email}^+^ = {email, user_id, first_name, last_name, password, user_type_id} = R2)
     364
     365||'''FD'''||'''Determinant'''||'''Superkey?'''||
     366||user_id -> first_name, last_name, email, password, user_type_id||user_id||Yes||
     367||email -> user_id||email||Yes||
     368
     369'''R2 is in BCNF.''' ✓
     370
     371=== R3 (!ResourceTypes) ===
     372
     373'''FDs:''' resource_type_id -> resource_type_name, is_physical; resource_type_name -> resource_type_id [[BR]]
     374'''Candidate keys:''' {resource_type_id}, {resource_type_name}
     375
     376||'''FD'''||'''Determinant'''||'''Superkey?'''||
     377||resource_type_id -> resource_type_name, is_physical||resource_type_id||Yes||
     378||resource_type_name -> resource_type_id||resource_type_name||Yes||
     379
     380'''R3 is in BCNF.''' ✓
     381
     382=== R4 (Locations) ===
     383
     384'''FDs:''' location_id -> building, room; {building, room} -> location_id [[BR]]
     385'''Candidate keys:''' {location_id}, {building, room}
     386
     387||'''FD'''||'''Determinant'''||'''Superkey?'''||
     388||location_id -> building, room||location_id||Yes||
     389||{building, room} -> location_id||{building, room}||Yes||
     390
     391'''R4 is in BCNF.''' ✓
     392
     393=== R5 (Resources) ===
     394
     395'''FDs:''' resource_id -> resource_name, resource_description, available_from, available_to, available_weekends, resource_type_id, location_id [[BR]]
     396'''Candidate keys:''' {resource_id}
     397
     398||'''FD'''||'''Determinant'''||'''Superkey?'''||
     399||resource_id -> resource_name, resource_description, ...||resource_id||Yes||
     400
     401'''R5 is in BCNF.''' ✓
     402
     403=== R6 (Reservations) ===
     404
     405'''FDs:''' reservation_id -> start_time, end_time, status, purpose, created_at, recurrence_group_id, user_id, approved_by, resource_id [[BR]]
     406'''Candidate keys:''' {reservation_id}
     407
     408||'''FD'''||'''Determinant'''||'''Superkey?'''||
     409||reservation_id -> start_time, end_time, ...||reservation_id||Yes||
     410
     411'''R6 is in BCNF.''' ✓
     412
     413'''Conclusion: All six relations are in BCNF.''' No further decomposition is needed. The decomposition preserves all functional dependencies and maintains the lossless join property.
     414
     415== Final Result and Discussion ==
     416
     417=== Normalized Relational Model ===
     418
     419The normalization process yields the following six relations, all in BCNF:
     420
     421 1. '''!UserTypes''' (user_type_id PK, user_type_name UNIQUE NOT NULL, user_type_description NOT NULL)
     422 2. '''Users''' (user_id PK, first_name NOT NULL, last_name NOT NULL, email UNIQUE NOT NULL, password NOT NULL, user_type_id NOT NULL FK->!UserTypes)
     423 3. '''!ResourceTypes''' (resource_type_id PK, resource_type_name UNIQUE NOT NULL, is_physical NOT NULL)
     424 4. '''Locations''' (location_id PK, building NOT NULL, room NOT NULL, UNIQUE(building, room))
     425 5. '''Resources''' (resource_id PK, resource_name NOT NULL, resource_description NOT NULL, available_from NOT NULL, available_to NOT NULL, available_weekends NOT NULL, resource_type_id NOT NULL FK->!ResourceTypes, location_id FK->Locations)
     426 6. '''Reservations''' (reservation_id PK, start_time NOT NULL, end_time NOT NULL, status NOT NULL, purpose NOT NULL, created_at NOT NULL, recurrence_group_id, user_id NOT NULL FK->Users, approved_by FK->Users, resource_id NOT NULL FK->Resources)
     427
     428=== Discussion ===
     429
     430The normalization process, starting from the universal de-normalized relation and proceeding through formal decomposition, produces '''exactly the same six relations''' as the Phase 2 relational design. This confirms that the original ER model (Phase 1) and its relational mapping (Phase 2) were already well-normalized.
     431
     432The key reasons for this outcome:
     433
     434 * The ER model correctly identified separate entities (!UserTypes, Users, !ResourceTypes, Locations, Resources, Reservations) corresponding to distinct real-world concepts, each with its own independent set of attributes.
     435 * Each entity was mapped to its own relation with a surrogate primary key, and relationships were represented through foreign keys.
     436 * No entity combined attributes from multiple independent concepts, so no transitive dependencies existed within any individual table.
     437
     438Since the normalization result matches the existing design, '''no changes to the database schema are required'''. The Phase 2 relational design and DDL scripts remain valid and will continue to be used for all subsequent project phases.