Changes between Version 14 and Version 15 of Normalization


Ignore:
Timestamp:
02/04/26 00:23:36 (5 days ago)
Author:
233144
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v14 v15  
    11= Normalization
    22
    3 == Initial de-normalized relation and functional dependencies
    4 
    5 Attributes with identical names originating from different relations were renamed using entity-based prefixes in order to avoid duplicate attribute names in the universal relation.
    6 
    7 R(user_id, username, password, email,
     3== 1. Definition of the Universal Relation
     4
     5We start from a single universal relation containing all attributes from the domain.
     6
     7Universal_Relation(
     8user_id, username, password, email,
    89admin_user_id,
    910component_id, component_name, component_brand, component_price, component_type, component_img_url,
     
    1516motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots,
    1617pc_case_cooler_max_height, pc_case_gpu_max_length,
    17 pc_case_storage_form_factor, case_storage_num_slots,
     18pc_case_storage_form_factor, pc_case_storage_num_slots,
    1819pc_case_ps_form_factor,
    1920pc_case_mobo_form_factor,
     
    3031rating_build_value,
    3132review_id, review_build_id, review_user_id, review_content, review_created_at,
    32 suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
    33 
    34 Before anything else, we need to note that pc_case_storage_form_factor (composite with case_storage_num_slots), pc_case_ps_form_factor, pc_case_mobo_form_factor, and cooler_cpu_socket are multivalued attributes.
    35 
    36 Now we will list the functional dependencies (the primary/composite keys are on the left side). For component_id the name of the proper subclass will be shown in parenthesis for better presentation.
    37 
    38 FD1: user_id -> username, password, email
    39 
    40 FD2: admin_user_id -> user_id (FK relationship)
    41 
    42 FD3: component_id -> component_name, component_brand, component_price, component_type, component_img_url
    43 
    44 FD4: component_id(cpu) -> cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp
    45 
    46 FD5: component_id(gpu) -> gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length
    47 
    48 FD6: component_id(memory) -> memory_type, memory_speed, memory_capacity, memory_modules
    49 
    50 FD7: component_id(storage) -> storage_type, storage_capacity, storage_form_factor
    51 
    52 FD8: component_id(power_supply) -> power_supply_type, power_supply_wattage, power_supply_form_factor
    53 
    54 FD9: component_id(motherboard) -> motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots
    55 
    56 FD10: component_id(pc_case) -> pc_case_cooler_max_height, pc_case_gpu_max_length
    57 
    58 FD11: component_id(cooler) -> cooler_type, cooler_height, cooler_max_tdp_supported
    59 
    60 FD12: component_id(memory_card) -> memory_card_num_slots, memory_card_interface
    61 
    62 FD13: component_id(optical_drive) -> optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed
    63 
    64 FD14: component_id(sound_card) -> sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel
    65 
    66 FD15: component_id(cables) -> cables_length_cm, cables_type
    67 
    68 FD16: component_id(network_adapter) -> network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas
    69 
    70 FD17: component_id(network_card) -> network_card_num_ports, network_card_speed, network_card_interface
    71 
    72 FD18: build_id -> build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
    73 
    74 FD19: build_id, component_id -> build_component_num_components
    75 
    76 FD20: build_id, user_id -> rating_build_value
    77 
    78 FD21: build_id, user_id -> (represents favorite_build relationship, no additional attributes)
    79 
    80 FD22: review_id -> review_build_id, review_user_id, review_content, review_created_at
    81 
    82 FD23: review_build_id, review_user_id -> review_id (alternate key constraint from UNIQUE)
    83 
    84 FD24: suggestion_id -> suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
    85 
    86 Left: user_id, admin_user_id, component_id, build_id, review_id, suggestion_id
    87 
    88 Left and right: build_user_id, user_id (via various FDs), review_build_id, review_user_id
    89 
    90 Right:
    91 username, password, email, component_name, component_brand, component_price, component_type, component_img_url, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length, memory_type, memory_speed, memory_capacity, memory_modules, storage_type, storage_capacity, storage_form_factor, power_supply_type, power_supply_wattage, power_supply_form_factor, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots, pc_case_cooler_max_height, pc_case_gpu_max_length, case_storage_num_slots, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_type, cooler_height, cooler_max_tdp_supported, cooler_cpu_socket, memory_card_num_slots, memory_card_interface, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel, cables_length_cm, cables_type, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas, network_card_num_ports, network_card_speed, network_card_interface, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved, build_component_num_components, rating_build_value, review_build_id, review_user_id, review_content, review_created_at, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
    92 
    93 Attributes that never appear on the right side (only left) are user_id, admin_user_id, component_id, build_id, review_id, suggestion_id. This means that they must be in every candidate key because nothing can determine them.
    94 
    95 Let's compute the closures of each individual left-side attribute to see what we can derive from each:
    96 
    97 {user_id}+ : By applying FD1 we add username, password, email. So {user_id}+ = {user_id, username, password, email}. This is NOT a superkey (missing all other attributes).
    98 
    99 {admin_user_id}+ : By applying FD2, admin_user_id → user_id. By applying FD1, user_id → username, password, email. So {admin_user_id}+ = {admin_user_id, user_id, username, password, email}. This is NOT a superkey (missing component_id, build_id, review_id, suggestion_id and their dependents).
    100 
    101 {component_id}+ : By applying FD3-FD17 we add component_name, component_brand, component_price, component_type, component_img_url, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length, memory_type, memory_speed, memory_capacity, memory_modules, storage_type, storage_capacity, storage_form_factor, power_supply_type, power_supply_wattage, power_supply_form_factor, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots, pc_case_cooler_max_height, pc_case_gpu_max_length, cooler_type, cooler_height, cooler_max_tdp_supported, memory_card_num_slots, memory_card_interface, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel, cables_length_cm, cables_type, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas, network_card_num_ports, network_card_speed, network_card_interface. So {component_id}+ contains all component attributes but is NOT a superkey (missing user_id, admin_user_id, build_id, review_id, suggestion_id and their dependents).
    102 
    103 {build_id}+ : By applying FD18 we add build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved. By applying FD19 we need component_id which we don't have. By applying FD20 and FD21 we need user_id which we don't have. So {build_id}+ = {build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved}. This is NOT a superkey.
    104 
    105 {review_id}+ : By applying FD22 we add review_build_id, review_user_id, review_content, review_created_at. We cannot derive build_id or user_id directly from the relation. So {review_id}+ = {review_id, review_build_id, review_user_id, review_content, review_created_at}. This is NOT a superkey.
    106 
    107 {suggestion_id}+ : By applying FD24 we add suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type. We cannot derive admin_user_id directly. So {suggestion_id}+ = {suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type}. This is NOT a superkey.
    108 
    109 Since no single left-side attribute can determine all others, we must combine them. Let's test the candidate key K = {user_id, admin_user_id, component_id, review_id, suggestion_id, build_id}.
    110 
    111 We now compute the closure K+
    112 
    113 Start with K+ = {user_id, admin_user_id, component_id, review_id, suggestion_id, build_id}
    114 
    115 By applying FD1 – we add:
    116 username, password, email
    117 
    118 By applying FD2 – we verify admin specialization (admin_user_id is FK to user_id, already in set)
    119 
    120 By applying FD3 – FD17, we add:
    121 component_name, component_brand, component_price, component_type, component_img_url,
    122 cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp,
    123 gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length,
    124 memory_type, memory_speed, memory_capacity, memory_modules,
    125 storage_type, storage_capacity, storage_form_factor,
    126 power_supply_type, power_supply_wattage, power_supply_form_factor,
    127 motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots,
    128 pc_case_cooler_max_height, pc_case_gpu_max_length,
    129 cooler_type, cooler_height, cooler_max_tdp_supported,
    130 memory_card_num_slots, memory_card_interface,
    131 optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed,
    132 sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel,
    133 cables_length_cm, cables_type,
    134 network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas,
    135 network_card_num_ports, network_card_speed, network_card_interface
    136 
    137 By applying FD18, we add:
    138 build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
    139 
    140 By applying FD19 (we have build_id and component_id), we add:
    141 build_component_num_components
    142 
    143 By applying FD20 and FD21 (we have build_id and user_id), we add:
    144 rating_build_value
    145 
    146 By applying FD22, we add:
    147 review_build_id, review_user_id, review_content, review_created_at
    148 
    149 By applying FD24, we add:
    150 suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
    151 
    152 After excluding multivalued attributes which we handle separately in 1NF, K+ contains all attributes of R, which means that K is a superkey.
    153 
    154 To verify that K = {user_id, admin_user_id, component_id, review_id, suggestion_id, build_id} is a candidate key, we test all proper subsets:
    155 
    156 {admin_user_id, component_id, review_id, suggestion_id, build_id}+ is missing user_id which blocks FD20 and FD21 (need user_id for build_id, user_id -> rating_build_value and favorite_build).
    157 
    158 {user_id, component_id, review_id, suggestion_id, build_id}+ is missing admin_user_id which blocks FD24 completely (need to derive suggestion_admin_id from admin_user_id).
    159 
    160 {user_id, admin_user_id, review_id, suggestion_id, build_id}+ is missing component_id which blocks FD19 (need build_id, component_id for build_component_num_components) and all component attributes.
    161 
    162 {user_id, admin_user_id, component_id, suggestion_id, build_id}+ is missing review_id which blocks FD22 (need review_id -> review attributes).
    163 
    164 {user_id, admin_user_id, component_id, review_id, build_id}+ is missing suggestion_id which blocks FD24 (need suggestion_id -> suggestion attributes).
    165 
    166 {user_id, admin_user_id, component_id, review_id, suggestion_id}+ is missing build_id which blocks FD18, FD19, FD20, FD21 (need build_id -> build attributes and build_id for various composite FDs).
    167 
    168 Therefore, K = {user_id, admin_user_id, component_id, review_id, suggestion_id, build_id} is the minimal candidate key (no proper subset is a superkey).
    169 
    170 The universal relation violates 1NF because the attributes pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, and cooler_cpu_socket represent multivalued attributes, and can contain multiple values for a single component_id. This will be resolved by decomposing them into separate relations.
    171 
    172 == 1NF Decomposition
    173 
    174 To achieve 1NF, we decompose the multivalued attributes from R into:
    175 
    176 component_id, pc_case_storage_form_factor -> case_storage_num_slots
    177 
    178 component_id, pc_case_ps_form_factor -> no non-key attributes
    179 
    180 component_id, pc_case_mobo_form_factor -> no non-key attributes
    181 
    182 component_id, cooler_cpu_socket -> no non-key attributes
    183 
    184 1NF is satisfied now. 2NF is not satisfied because of partial dependencies. We can see this through the functional dependencies:
    185 
    186 FD1: user_id is part of the key, but these attributes such as username, password, email depend only on user_id.
    187 
    188 FD2: admin_user_id is part of the key, but user_id depends only on admin_user_id.
    189 
    190 FD3-FD17: component_id is part of the key, but these attributes such as component_name, component_brand, component_price etc. depend only on component_id.
    191 
    192 FD18: build_id is part of the key, but these attributes such as build_user_id, build_name etc. depend only on build_id.
    193 
    194 FD19: (build_id, component_id) is part of the key, but build_component_num_components depends on (build_id, component_id).
    195 
    196 FD20: (build_id, user_id) is part of the key, but rating_build_value depends on (build_id, user_id).
    197 
    198 FD21: (build_id, user_id) is part of the key, but represents favorite_build (no attributes).
    199 
    200 FD22: review_id is part of the key, but these attributes such as review_build_id, review_user_id, review_content, review_created_at depend only on review_id.
    201 
    202 FD24: suggestion_id is part of the key, but these attributes such as suggestion_user_id, suggestion_admin_id etc. depend only on suggestion_id.
    203 
    204 We will decompose by creating new relations from R following FD1, FD2 to FD24 where the attributes will depend only on the determinant attribute(s), which will become the primary key:
    205 
    206 user_id -> username, password, email
    207 
    208 admin_user_id -> user_id
    209 
    210 component_id -> component_name, component_brand, component_price, component_type, component_img_url
    211 
    212 component_id -> cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp
    213 
    214 component_id -> gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length
    215 
    216 component_id -> memory_type, memory_speed, memory_capacity, memory_modules
    217 
    218 component_id -> storage_type, storage_capacity, storage_form_factor
    219 
    220 component_id -> power_supply_type, power_supply_wattage, power_supply_form_factor
    221 
    222 component_id -> motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots
    223 
    224 component_id -> pc_case_cooler_max_height, pc_case_gpu_max_length
    225 
    226 build_id -> build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
    227 
    228 build_id, component_id -> build_component_num_components
    229 
    230 build_id, user_id -> rating_build_value
    231 
    232 build_id, user_id -> (represents favorite_build)
    233 
    234 review_id -> review_build_id, review_user_id, review_content, review_created_at
    235 
    236 suggestion_id -> suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
    237 
    238 Primary key in all of these is the attribute(s) on the left side.
    239 
    240 == 2NF Decomposition
    241 
    242 All these partial dependencies are addressed in 2NF. We will solve these partial dependencies by creating new relations where each determinant becomes a primary key:
    243 
    244 R1 { user_id, username, password, email } where PK = user_id - BCNF
    245 
    246 R2 { admin_user_id, user_id } where PK = admin_user_id, FK = user_id -> R1.user_id - BCNF
    247 
    248 R3 { component_id, component_name, component_brand, component_price, component_type, component_img_url } where PK = component_id - BCNF
    249 
    250 R4 { component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp } where PK = component_id - BCNF
    251 
    252 R5 { component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length } where PK = component_id - BCNF
    253 
    254 R6 { component_id, memory_type, memory_speed, memory_capacity, memory_modules } where PK = component_id - BCNF
    255 
    256 R7 { component_id, storage_type, storage_capacity, storage_form_factor } where PK = component_id - BCNF
    257 
    258 R8 { component_id, power_supply_type, power_supply_wattage, power_supply_form_factor } where PK = component_id - BCNF
    259 
    260 R9 { component_id, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots } where PK = component_id - BCNF
    261 
    262 R10 { component_id, pc_case_cooler_max_height, pc_case_gpu_max_length } where PK = component_id - BCNF
    263 
    264 R11 { build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved } where PK = build_id - BCNF
    265 
    266 R12 { build_id, component_id, build_component_num_components } where PK = (build_id, component_id) - BCNF
    267 
    268 R13 { build_id, user_id, rating_build_value } where PK = (build_id, user_id) - BCNF
    269 
    270 R14 { build_id, user_id } where PK = (build_id, user_id) - BCNF
    271 
    272 R15 { component_id, cooler_type, cooler_height, cooler_max_tdp_supported } where PK = component_id - BCNF
    273 
    274 R16 { component_id, memory_card_num_slots, memory_card_interface } where PK = component_id - BCNF
    275 
    276 R17 { component_id, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed } where PK = component_id - BCNF
    277 
    278 R18 { component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel } where PK = component_id - BCNF
    279 
    280 R19 { component_id, cables_length_cm, cables_type } where PK = component_id - BCNF
    281 
    282 R20 { component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas } where PK = component_id - BCNF
    283 
    284 R21 { component_id, network_card_num_ports, network_card_speed, network_card_interface } where PK = component_id - BCNF
    285 
    286 R22 { review_id, review_build_id, review_user_id, review_content, review_created_at } where PK = review_id, Alt Key = (review_build_id, review_user_id) - BCNF
    287 
    288 R23 { suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type } where PK = suggestion_id - BCNF
    289 
    290 The remainder of R { component_id, review_id, suggestion_id, build_id, user_id, admin_user_id } where PK = K (component_id, review_id, suggestion_id, build_id, user_id, admin_user_id)
    291 
    292 2NF is satisfied for all relations. All partial dependencies have been eliminated. No transitive dependencies can exist in relations with only key attributes or attributes derived entirely from the key.
    293 
    294 All relations are already in BCNF since every determinant of every functional dependency is a candidate key of its respective relation.
    295 
    296 == Final BCNF relations
    297 
    298 Users { user_id, username, password, email }
    299 
    300 Admins { admin_user_id, user_id (FK to Users.user_id) }
    301 
    302 Components { component_id, component_name, component_brand, component_price, component_type, component_img_url }
    303 
    304 Cpu { component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp }
    305 
    306 Gpu { component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length }
    307 
    308 Memory { component_id, memory_type, memory_speed, memory_capacity, memory_modules }
    309 
    310 Storage { component_id, storage_type, storage_capacity, storage_form_factor }
    311 
    312 Power_Supply { component_id, power_supply_type, power_supply_wattage, power_supply_form_factor }
    313 
    314 Motherboard { component_id, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots }
    315 
    316 Pc_Case { component_id, pc_case_cooler_max_height, pc_case_gpu_max_length }
    317 
    318 Case_Storage_Form_Factors { component_id, pc_case_storage_form_factor, case_storage_num_slots }
    319 
    320 Case_Ps_Form_Factors { component_id, pc_case_ps_form_factor }
    321 
    322 Case_Mobo_Form_Factors { component_id, pc_case_mobo_form_factor }
    323 
    324 Cooler { component_id, cooler_type, cooler_height, cooler_max_tdp_supported }
    325 
    326 Cooler_Cpu_Sockets { component_id, cooler_cpu_socket }
    327 
    328 Memory_Card { component_id, memory_card_num_slots, memory_card_interface }
    329 
    330 Optical_Drive { component_id, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed }
    331 
    332 Sound_Card { component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel }
    333 
    334 Cables { component_id, cables_length_cm, cables_type }
    335 
    336 Network_Adapter { component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas }
    337 
    338 Network_Card { component_id, network_card_num_ports, network_card_speed, network_card_interface }
    339 
    340 Build { build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved }
    341 
    342 Build_Component { build_id, component_id, build_component_num_components }
    343 
    344 Rating_Build { build_id, user_id, rating_build_value }
    345 
    346 Favorite_Build { build_id, user_id }
    347 
    348 Review { review_id, review_build_id, review_user_id, review_content, review_created_at }
    349 
    350 Suggestions { suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type }
    351 
     33suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     34)
     35
     36== 2. Functional Dependencies
     37
     38We identify all functional dependencies that hold in the universal relation:
     39
     40F = {
     41
     42FD1: user_id → username, password, email
     43
     44FD2: admin_user_id → ∅
     45
     46FD3: component_id → component_name, component_brand, component_price, component_type, component_img_url
     47
     48FD4: component_id → cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp
     49
     50FD5: component_id → gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length
     51
     52FD6: component_id → memory_type, memory_speed, memory_capacity, memory_modules
     53
     54FD7: component_id → storage_type, storage_capacity, storage_form_factor
     55
     56FD8: component_id → power_supply_type, power_supply_wattage, power_supply_form_factor
     57
     58FD9: component_id → motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots
     59
     60FD10: component_id → pc_case_cooler_max_height, pc_case_gpu_max_length
     61
     62FD11: component_id → cooler_type, cooler_height, cooler_max_tdp_supported
     63
     64FD12: component_id → memory_card_num_slots, memory_card_interface
     65
     66FD13: component_id → optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed
     67
     68FD14: component_id → sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel
     69
     70FD15: component_id → cables_length_cm, cables_type
     71
     72FD16: component_id → network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas
     73
     74FD17: component_id → network_card_num_ports, network_card_speed, network_card_interface
     75
     76FD18: build_id → build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
     77
     78FD19: (build_id, component_id) → build_component_num_components
     79
     80FD20: (build_id, user_id) → rating_build_value
     81
     82FD21: (build_id, user_id) → ∅ (represents favorite_build relationship)
     83
     84FD22: review_id → review_build_id, review_user_id, review_content, review_created_at
     85
     86FD23: suggestion_id → suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     87
     88FD24: (component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots
     89
     90FD25: (component_id, pc_case_mobo_form_factor) → ∅
     91
     92FD26: (component_id, pc_case_ps_form_factor) → ∅
     93
     94FD27: (component_id, cooler_cpu_socket) → ∅
     95
     96}
     97
     98== 3. Candidate Keys and Primary Key
     99
     100=== 3.1 Determination of Candidate Keys
     101
     102To find a candidate key, we must find a minimal set of attributes whose closure contains all attributes of the relation.
     103
     104=== 3.2 Attribute Classification (Left / Right Side)
     105
     106|| Attribute =||= Left Side =||= Right Side =||= Classification =||
     107|| user_id || ✓ (FD1) || ✗ || Left only ||
     108|| username || ✗ || ✓ (FD1) || Right only ||
     109|| password || ✗ || ✓ (FD1) || Right only ||
     110|| email || ✗ || ✓ (FD1) || Right only ||
     111|| admin_user_id || ✓ (FD2) || ✗ || Left only ||
     112|| component_id || ✓ (FD3-FD17, FD24-FD27) || ✗ || Left only ||
     113|| component_name || ✗ || ✓ (FD3) || Right only ||
     114|| component_brand || ✗ || ✓ (FD3) || Right only ||
     115|| component_price || ✗ || ✓ (FD3) || Right only ||
     116|| component_type || ✗ || ✓ (FD3) || Right only ||
     117|| component_img_url || ✗ || ✓ (FD3) || Right only ||
     118|| [CPU attributes] || ✗ || ✓ (FD4) || Right only ||
     119|| [GPU attributes] || ✗ || ✓ (FD5) || Right only ||
     120|| [Memory attributes] || ✗ || ✓ (FD6) || Right only ||
     121|| [Storage attributes] || ✗ || ✓ (FD7) || Right only ||
     122|| [Power Supply attributes] || ✗ || ✓ (FD8) || Right only ||
     123|| [Motherboard attributes] || ✗ || ✓ (FD9) || Right only ||
     124|| pc_case_cooler_max_height || ✗ || ✓ (FD10) || Right only ||
     125|| pc_case_gpu_max_length || ✗ || ✓ (FD10) || Right only ||
     126|| pc_case_storage_form_factor || ✓ (FD24) || ✗ || Left only ||
     127|| pc_case_storage_num_slots || ✗ || ✓ (FD24) || Right only ||
     128|| pc_case_ps_form_factor || ✓ (FD26) || ✗ || Left only ||
     129|| pc_case_mobo_form_factor || ✓ (FD25) || ✗ || Left only ||
     130|| cooler_type || ✗ || ✓ (FD11) || Right only ||
     131|| cooler_height || ✗ || ✓ (FD11) || Right only ||
     132|| cooler_max_tdp_supported || ✗ || ✓ (FD11) || Right only ||
     133|| cooler_cpu_socket || ✓ (FD27) || ✗ || Left only ||
     134|| [Memory Card attributes] || ✗ || ✓ (FD12) || Right only ||
     135|| [Optical Drive attributes] || ✗ || ✓ (FD13) || Right only ||
     136|| [Sound Card attributes] || ✗ || ✓ (FD14) || Right only ||
     137|| [Cables attributes] || ✗ || ✓ (FD15) || Right only ||
     138|| [Network Adapter attributes] || ✗ || ✓ (FD16) || Right only ||
     139|| [Network Card attributes] || ✗ || ✓ (FD17) || Right only ||
     140|| build_id || ✓ (FD18-FD21) || ✗ || Left only ||
     141|| build_user_id || ✗ || ✓ (FD18) || Right only ||
     142|| build_name || ✗ || ✓ (FD18) || Right only ||
     143|| build_created_at || ✗ || ✓ (FD18) || Right only ||
     144|| build_description || ✗ || ✓ (FD18) || Right only ||
     145|| build_total_price || ✗ || ✓ (FD18) || Right only ||
     146|| build_is_approved || ✗ || ✓ (FD18) || Right only ||
     147|| build_component_num_components || ✗ || ✓ (FD19) || Right only ||
     148|| rating_build_value || ✗ || ✓ (FD20) || Right only ||
     149|| review_id || ✓ (FD22) || ✗ || Left only ||
     150|| review_build_id || ✗ || ✓ (FD22) || Right only ||
     151|| review_user_id || ✗ || ✓ (FD22) || Right only ||
     152|| review_content || ✗ || ✓ (FD22) || Right only ||
     153|| review_created_at || ✗ || ✓ (FD22) || Right only ||
     154|| suggestion_id || ✓ (FD23) || ✗ || Left only ||
     155|| suggestion_user_id || ✗ || ✓ (FD23) || Right only ||
     156|| suggestion_admin_id || ✗ || ✓ (FD23) || Right only ||
     157|| suggestion_link || ✗ || ✓ (FD23) || Right only ||
     158|| suggestion_admin_comment || ✗ || ✓ (FD23) || Right only ||
     159|| suggestion_description || ✗ || ✓ (FD23) || Right only ||
     160|| suggestion_status || ✗ || ✓ (FD23) || Right only ||
     161|| suggestion_component_type || ✗ || ✓ (FD23) || Right only ||
     162
     163
     164=== 3.3 Attributes That Appear ONLY on the Left Side
     165
     166The following attributes appear only on the left side of functional dependencies and never on the right side:
     167
     168- user_id – must be part of every candidate key
     169- component_id – must be part of every candidate key
     170- build_id – must be part of every candidate key
     171- review_id – must be part of every candidate key
     172- suggestion_id – must be part of every candidate key
     173- pc_case_storage_form_factor – must be part of every candidate key
     174- pc_case_ps_form_factor – must be part of every candidate key
     175- pc_case_mobo_form_factor – must be part of every candidate key
     176- cooler_cpu_socket – must be part of every candidate key
     177- admin_user_id – must be part of every candidate key
     178
     179=== 3.4 Closure Computation
     180
     181**Step 1:** We start with {user_id, component_id, build_id, review_id, suggestion_id, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, admin_user_id} and compute the closure:
     182
     183{user_id, component_id, build_id, review_id, suggestion_id, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, admin_user_id}⁺:
     184
     185- From FD1 (user_id → username, password, email): We obtain username, password, email
     186- From FD2 (admin_user_id → ∅): No new attributes
     187- From FD3–FD17 (component_id → ...): We obtain component_name, component_brand, component_price, component_type, component_img_url, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length, memory_type, memory_speed, memory_capacity, memory_modules, storage_type, storage_capacity, storage_form_factor, power_supply_type, power_supply_wattage, power_supply_form_factor, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots, pc_case_cooler_max_height, pc_case_gpu_max_length, cooler_type, cooler_height, cooler_max_tdp_supported, memory_card_num_slots, memory_card_interface, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel, cables_length_cm, cables_type, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas, network_card_num_ports, network_card_speed, network_card_interface
     188- From FD18 (build_id → ...): We obtain build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
     189- From FD19 ((build_id, component_id) → build_component_num_components): We obtain build_component_num_components (both build_id and component_id already in closure)
     190- From FD20 ((build_id, user_id) → rating_build_value): We obtain rating_build_value (both build_id and user_id already in closure)
     191- From FD21 ((build_id, user_id) → ∅): No new attributes
     192- From FD22 (review_id → ...): We obtain review_build_id, review_user_id, review_content, review_created_at
     193- From FD23 (suggestion_id → ...): We obtain suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     194- From FD24 ((component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots): We obtain pc_case_storage_num_slots (both attributes already in closure)
     195- From FD25–FD27 (composite FDs with empty RHS): No new attributes
     196
     197Closure = Universal_Relation ✓ (all attributes are present)
     198
     199=== 3.5 Minimality Check
     200
     201Testing proper subsets of K = {user_id, component_id, build_id, review_id, suggestion_id, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, admin_user_id}:
     202
     203|| Subset =||= Closure Equals Universal_Relation? =||= Justification =||
     204|| K − {user_id} || ✗ NO || Cannot derive username, password, email (FD1 requires user_id) ||
     205|| K − {component_id} || ✗ NO || Cannot derive component attributes (FD3–FD17 require component_id) ||
     206|| K − {build_id} || ✗ NO || Cannot derive build attributes (FD18 requires build_id) ||
     207|| K − {review_id} || ✗ NO || Cannot derive review attributes (FD22 requires review_id) ||
     208|| K − {suggestion_id} || ✗ NO || Cannot derive suggestion attributes (FD23 requires suggestion_id) ||
     209|| K − {pc_case_storage_form_factor} || ✗ NO || FD24 requires pc_case_storage_form_factor ||
     210|| K − {pc_case_ps_form_factor} || ✗ NO || FD26 requires pc_case_ps_form_factor ||
     211|| K − {pc_case_mobo_form_factor} || ✗ NO || FD25 requires pc_case_mobo_form_factor ||
     212|| K − {cooler_cpu_socket} || ✗ NO || FD27 requires cooler_cpu_socket ||
     213|| K − {admin_user_id} || ✗ NO || admin_user_id is a left-only attribute and must be in every candidate key ||
     214
     215
     216**Conclusion:** K = {user_id, component_id, build_id, review_id, suggestion_id, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, admin_user_id} is minimal and is the only candidate key.
     217
     218=== 3.6 Choice of Primary Key
     219
     220**Chosen Primary Key:** {user_id, component_id, build_id, review_id, suggestion_id, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, admin_user_id}
     221
     222**Justification:** This is the primary key (minimal candidate key) because only with these attributes can we derive all remaining attributes from the universal relation through the closure of functional dependencies.
     223
     224---
     225
     226== 4. 1NF Decomposition
     227
     228=== 4.1 1NF Violation Identification
     229
     230The relation violates 1NF because the attributes pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, and cooler_cpu_socket represent multivalued attributes. Each component_id can have multiple values for each of these attributes.
     231
     232=== 4.2 1NF Decomposition
     233
     234==== Relation R1: Case_Storage_Form_Factors
     235
     236Case_Storage_Form_Factors(component_id, pc_case_storage_form_factor, pc_case_storage_num_slots)
     237PK: (component_id, pc_case_storage_form_factor)
     238
     239**Attributes Included:** component_id, pc_case_storage_form_factor, pc_case_storage_num_slots
     240
     241**Functional Dependency Enforced:** FD24: (component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots
     242
     243**Lossless Join Check:**
     244- This relation is decomposed directly from the universal relation by extracting the multivalued attribute group pc_case_storage_form_factor
     245- The composite primary key (component_id, pc_case_storage_form_factor) uniquely identifies each tuple
     246- When joined back with the main relation via component_id, no spurious tuples are introduced
     247- The decomposition captures the exact relationship defined by FD24
     248- **Result: LOSSLESS ✓**
     249
     250**Dependency Preservation Check:**
     251- FD24: (component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots
     252  - Determinant: (component_id, pc_case_storage_form_factor)
     253  - Dependent: pc_case_storage_num_slots
     254  - All attributes of FD24 appear together in this relation ✓
     255- The functional dependency is directly enforceable within this schema
     256- **Result: PRESERVED ✓**
     257
     258---
     259
     260==== Relation R2: Case_Ps_Form_Factors
     261
     262Case_Ps_Form_Factors(component_id, pc_case_ps_form_factor)
     263PK: (component_id, pc_case_ps_form_factor)
     264
     265**Attributes Included:** component_id, pc_case_ps_form_factor
     266
     267**Functional Dependency Enforced:** FD26: (component_id, pc_case_ps_form_factor) → ∅
     268
     269**Lossless Join Check:**
     270- Decomposed directly from the multivalued attribute pc_case_ps_form_factor
     271- The primary key (component_id, pc_case_ps_form_factor) uniquely identifies the relationship
     272- Joining with the main relation on component_id preserves all original tuples
     273- No information loss occurs during decomposition or reconstruction
     274- **Result: LOSSLESS ✓**
     275
     276**Dependency Preservation Check:**
     277- FD26: (component_id, pc_case_ps_form_factor) → ∅
     278  - This is a relationship-only functional dependency with empty RHS
     279  - The determinant (component_id, pc_case_ps_form_factor) is present as the primary key
     280  - All attributes involved in FD26 are contained in this relation ✓
     281- **Result: PRESERVED ✓**
     282
     283---
     284
     285==== Relation R3: Case_Mobo_Form_Factors
     286
     287Case_Mobo_Form_Factors(component_id, pc_case_mobo_form_factor)
     288PK: (component_id, pc_case_mobo_form_factor)
     289
     290**Attributes Included:** component_id, pc_case_mobo_form_factor
     291
     292**Functional Dependency Enforced:** FD25: (component_id, pc_case_mobo_form_factor) → ∅
     293
     294**Lossless Join Check:**
     295- Decomposed from the multivalued attribute pc_case_mobo_form_factor
     296- The composite key fully represents the relationship between component and motherboard form factor
     297- Natural join on component_id with the main relation produces no spurious tuples
     298- Complete reconstruction of the original relationship is possible
     299- **Result: LOSSLESS ✓**
     300
     301**Dependency Preservation Check:**
     302- FD25: (component_id, pc_case_mobo_form_factor) → ∅
     303  - The relationship-only FD is preserved through the composite primary key
     304  - All attributes of FD25 present in this schema ✓
     305- **Result: PRESERVED ✓**
     306
     307---
     308
     309==== Relation R4: Cooler_Cpu_Sockets
     310
     311Cooler_Cpu_Sockets(component_id, cooler_cpu_socket)
     312PK: (component_id, cooler_cpu_socket)
     313
     314**Attributes Included:** component_id, cooler_cpu_socket
     315
     316**Functional Dependency Enforced:** FD27: (component_id, cooler_cpu_socket) → ∅
     317
     318**Lossless Join Check:**
     319- Decomposed directly from the multivalued attribute cooler_cpu_socket
     320- The primary key captures the complete relationship
     321- Rejoining via component_id preserves all original tuples without duplication
     322- No information loss in decomposition or reconstruction
     323- **Result: LOSSLESS ✓**
     324
     325**Dependency Preservation Check:**
     326- FD27: (component_id, cooler_cpu_socket) → ∅
     327  - The relationship-only FD is preserved by the composite key structure
     328  - All attributes involved in FD27 are present ✓
     329- **Result: PRESERVED ✓**
     330
     331---
     332
     333==== Relation R5: Universal_Relation_1NF
     334
     335Universal_Relation_1NF(
     336  user_id, username, password, email,
     337  admin_user_id,
     338  component_id, component_name, component_brand, component_price, component_type, component_img_url,
     339  cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp,
     340  gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length,
     341  memory_type, memory_speed, memory_capacity, memory_modules,
     342  storage_type, storage_capacity, storage_form_factor,
     343  power_supply_type, power_supply_wattage, power_supply_form_factor,
     344  motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots,
     345  pc_case_cooler_max_height, pc_case_gpu_max_length,
     346  pc_case_storage_num_slots,
     347  cooler_type, cooler_height, cooler_max_tdp_supported,
     348  memory_card_num_slots, memory_card_interface,
     349  optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed,
     350  sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel,
     351  cables_length_cm, cables_type,
     352  network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas,
     353  network_card_num_ports, network_card_speed, network_card_interface,
     354  build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved,
     355  build_component_num_components,
     356  rating_build_value,
     357  review_id, review_build_id, review_user_id, review_content, review_created_at,
     358  suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     359)
     360PK: (user_id, component_id, build_id, review_id, suggestion_id, admin_user_id)
     361
     362**Attributes Included:** All original attributes except the multivalued ones (pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket)
     363
     364**Functional Dependencies Enforced:** FD1–FD24 (all except FD25–FD27)
     365
     366**Lossless Join Check:**
     367- The four decomposed multivalued relations can be joined back to this relation via component_id
     368- Each tuple in this main relation corresponds to a set of tuples in each multivalued relation
     369- The natural join R5 ⋈ R1 ⋈ R2 ⋈ R3 ⋈ R4 reconstructs the original universal relation without spurious tuples
     370- All join paths are on component_id, a common attribute present in all relations
     371- **Result: LOSSLESS ✓**
     372
     373**Dependency Preservation Check:**
     374- FD1: user_id → username, password, email — All attributes present ✓
     375- FD2: admin_user_id → ∅ — Determinant present ✓
     376- FD3–FD23: component_id or composite keys → dependent attributes — All attributes present ✓
     377- FD24: (component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots — pc_case_storage_num_slots retained ✓
     378- All functional dependencies relevant to this relation are preserved
     379- **Result: PRESERVED ✓**
     380
     381---
     382
     383== 5. 2NF Decomposition
     384
     385=== 5.1 2NF Violation Analysis
     386
     387The Universal_Relation_1NF (R5) violates 2NF due to partial dependencies.
     388
     389**Primary Key:** (user_id, component_id, build_id, review_id, suggestion_id, admin_user_id)
     390
     391A partial dependency exists when a non-key attribute depends on only a **proper subset** of the composite primary key rather than the entire key.
     392
     393**Identified Partial Dependencies:**
     394
     395|| FD =||= Determinant =||= Proper Subset? =||= Non-key Attributes Dependent =||= 2NF Violation? =||
     396|| FD1 || user_id || ✓ YES || username, password, email || ✓ YES ||
     397|| FD2 || admin_user_id || ✓ YES || (specialization) || ✓ YES ||
     398|| FD3–FD17 || component_id || ✓ YES || component attributes || ✓ YES ||
     399|| FD18 || build_id || ✓ YES || build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved || ✓ YES ||
     400|| FD22 || review_id || ✓ YES || review_build_id, review_user_id, review_content, review_created_at || ✓ YES ||
     401|| FD23 || suggestion_id || ✓ YES || suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type || ✓ YES ||
     402|| FD19 || (build_id, component_id) || ✓ YES || build_component_num_components || ✓ YES ||
     403|| FD20 || (build_id, user_id) || ✓ YES || rating_build_value || ✓ YES ||
     404|| FD21 || (build_id, user_id) || ✓ YES || (relationship only) || ✓ YES ||
     405
     406=== 5.2 2NF Decomposition
     407
     408We eliminate partial dependencies by creating new relations where each partial dependency determinant becomes a primary key.
     409
     410---
     411
     412==== 2NF Relation 1: Users
     413
     414Users(user_id, username, password, email)
     415PK: user_id
     416
     417**Derived From:** FD1 (user_id → username, password, email)
     418
     419**Functional Dependency Enforced:** FD1
     420
     421**Lossless Join Check:**
     422- Before decomposition, user_id was part of the composite key in Universal_Relation_1NF
     423- Now user_id becomes the sole primary key in Users
     424- Intersection of Users and Universal_Relation_1NF: I = {user_id}
     425- FD1 guarantees: user_id → username, password, email
     426- The join condition is on user_id, which is a candidate key for Users
     427- Natural join Users ⋈ Universal_Relation_1NF on user_id produces no spurious tuples
     428- All original tuples can be reconstructed: ✓
     429- **Result: LOSSLESS ✓**
     430
     431**Dependency Preservation Check:**
     432- FD1: user_id → username, password, email
     433  - Determinant (user_id) and all dependent attributes (username, password, email) are present in Users ✓
     434  - The FD is directly enforceable within this relation
     435- No other FD involves only user_id and its dependents in Universal_Relation_1NF
     436- **Result: PRESERVED ✓**
     437
     438---
     439
     440==== 2NF Relation 2: Admins
     441
     442Admins(admin_user_id)
     443PK: admin_user_id
     444FK: admin_user_id → Users.user_id
     445
     446**Derived From:** FD2 (admin_user_id → ∅)
     447
     448**Functional Dependency Enforced:** FD2
     449
     450**Lossless Join Check:**
     451- admin_user_id was part of the composite key in Universal_Relation_1NF
     452- Now admin_user_id becomes the sole primary key in Admins
     453- Intersection: I = {admin_user_id}
     454- FD2 is a relationship-only dependency with empty dependent set
     455- The join Admins ⋈ Universal_Relation_1NF on admin_user_id reconstructs the relationship
     456- No spurious tuples introduced
     457- **Result: LOSSLESS ✓**
     458
     459**Dependency Preservation Check:**
     460- FD2: admin_user_id → ∅
     461  - The determinant (admin_user_id) is the primary key ✓
     462  - This relationship-only FD is preserved through the key structure
     463- **Result: PRESERVED ✓**
     464
     465---
     466
     467==== 2NF Relation 3: Components
     468
     469Components(component_id, component_name, component_brand, component_price, component_type, component_img_url)
     470PK: component_id
     471
     472**Derived From:** FD3 (component_id → component_name, component_brand, component_price, component_type, component_img_url)
     473
     474**Functional Dependency Enforced:** FD3
     475
     476**Lossless Join Check:**
     477- component_id was part of the composite key in Universal_Relation_1NF
     478- Now component_id becomes the sole primary key in Components
     479- Intersection: I = {component_id}
     480- FD3 guarantees: component_id uniquely determines all dependent attributes
     481- Join Components ⋈ Universal_Relation_1NF on component_id is lossless
     482- No spurious tuples introduced
     483- **Result: LOSSLESS ✓**
     484
     485**Dependency Preservation Check:**
     486- FD3: component_id → component_name, component_brand, component_price, component_type, component_img_url
     487  - All attributes of FD3 present in Components ✓
     488  - The FD is directly enforceable within this relation
     489- **Result: PRESERVED ✓**
     490
     491---
     492
     493==== 2NF Relation 4: Cpu
     494
     495Cpu(component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp)
     496PK: component_id
     497FK: component_id → Components.component_id
     498
     499**Derived From:** FD4 (component_id → cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp)
     500
     501**Functional Dependency Enforced:** FD4
     502
     503**Lossless Join Check:**
     504- component_id is a proper subset of the original composite key
     505- component_id becomes the primary key in Cpu
     506- Intersection: I = {component_id}
     507- FD4 ensures all non-key attributes are uniquely determined by component_id
     508- Join with Universal_Relation_1NF on component_id is lossless
     509- **Result: LOSSLESS ✓**
     510
     511**Dependency Preservation Check:**
     512- FD4: component_id → cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp
     513  - All attributes present in Cpu ✓
     514  - Directly enforceable
     515- **Result: PRESERVED ✓**
     516
     517---
     518
     519==== 2NF Relation 5: Gpu
     520
     521Gpu(component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length)
     522PK: component_id
     523FK: component_id → Components.component_id
     524
     525**Derived From:** FD5
     526
     527**Lossless Join Check:** LOSSLESS ✓ (same reasoning as Cpu)
     528
     529**Dependency Preservation Check:** FD5 directly enforceable ✓ PRESERVED ✓
     530
     531---
     532
     533==== 2NF Relation 6: Memory
     534
     535Memory(component_id, memory_type, memory_speed, memory_capacity, memory_modules)
     536PK: component_id
     537FK: component_id → Components.component_id
     538
     539**Derived From:** FD6
     540
     541**Lossless Join Check:** LOSSLESS ✓
     542
     543**Dependency Preservation Check:** PRESERVED ✓
     544
     545---
     546
     547==== 2NF Relation 7: Storage
     548
     549Storage(component_id, storage_type, storage_capacity, storage_form_factor)
     550PK: component_id
     551FK: component_id → Components.component_id
     552
     553**Derived From:** FD7
     554
     555**Lossless Join Check:** LOSSLESS ✓
     556
     557**Dependency Preservation Check:** PRESERVED ✓
     558
     559---
     560
     561==== 2NF Relation 8: Power_Supply
     562
     563Power_Supply(component_id, power_supply_type, power_supply_wattage, power_supply_form_factor)
     564PK: component_id
     565FK: component_id → Components.component_id
     566
     567**Derived From:** FD8
     568
     569**Lossless Join Check:** LOSSLESS ✓
     570
     571**Dependency Preservation Check:** PRESERVED ✓
     572
     573---
     574
     575==== 2NF Relation 9: Motherboard
     576
     577Motherboard(component_id, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots)
     578PK: component_id
     579FK: component_id → Components.component_id
     580
     581**Derived From:** FD9
     582
     583**Lossless Join Check:** LOSSLESS ✓
     584
     585**Dependency Preservation Check:** PRESERVED ✓
     586
     587---
     588
     589==== 2NF Relation 10: Pc_Case
     590
     591Pc_Case(component_id, pc_case_cooler_max_height, pc_case_gpu_max_length)
     592PK: component_id
     593FK: component_id → Components.component_id
     594
     595**Derived From:** FD10
     596
     597**Lossless Join Check:** LOSSLESS ✓
     598
     599**Dependency Preservation Check:** PRESERVED ✓
     600
     601---
     602
     603==== 2NF Relation 11: Cooler
     604
     605Cooler(component_id, cooler_type, cooler_height, cooler_max_tdp_supported)
     606PK: component_id
     607FK: component_id → Components.component_id
     608
     609**Derived From:** FD11
     610
     611**Lossless Join Check:** LOSSLESS ✓
     612
     613**Dependency Preservation Check:** PRESERVED ✓
     614
     615---
     616
     617==== 2NF Relation 12: Memory_Card
     618
     619Memory_Card(component_id, memory_card_num_slots, memory_card_interface)
     620PK: component_id
     621FK: component_id → Components.component_id
     622
     623**Derived From:** FD12
     624
     625**Lossless Join Check:** LOSSLESS ✓
     626
     627**Dependency Preservation Check:** PRESERVED ✓
     628
     629---
     630
     631==== 2NF Relation 13: Optical_Drive
     632
     633Optical_Drive(component_id, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed)
     634PK: component_id
     635FK: component_id → Components.component_id
     636
     637**Derived From:** FD13
     638
     639**Lossless Join Check:** LOSSLESS ✓
     640
     641**Dependency Preservation Check:** PRESERVED ✓
     642
     643---
     644
     645==== 2NF Relation 14: Sound_Card
     646
     647Sound_Card(component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel)
     648PK: component_id
     649FK: component_id → Components.component_id
     650
     651**Derived From:** FD14
     652
     653**Lossless Join Check:** LOSSLESS ✓
     654
     655**Dependency Preservation Check:** PRESERVED ✓
     656
     657---
     658
     659==== 2NF Relation 15: Cables
     660
     661Cables(component_id, cables_length_cm, cables_type)
     662PK: component_id
     663FK: component_id → Components.component_id
     664
     665**Derived From:** FD15
     666
     667**Lossless Join Check:** LOSSLESS ✓
     668
     669**Dependency Preservation Check:** PRESERVED ✓
     670
     671---
     672
     673==== 2NF Relation 16: Network_Adapter
     674
     675Network_Adapter(component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas)
     676PK: component_id
     677FK: component_id → Components.component_id
     678
     679**Derived From:** FD16
     680
     681**Lossless Join Check:** LOSSLESS ✓
     682
     683**Dependency Preservation Check:** PRESERVED ✓
     684
     685---
     686
     687==== 2NF Relation 17: Network_Card
     688
     689Network_Card(component_id, network_card_num_ports, network_card_speed, network_card_interface)
     690PK: component_id
     691FK: component_id → Components.component_id
     692
     693**Derived From:** FD17
     694
     695**Lossless Join Check:** LOSSLESS ✓
     696
     697**Dependency Preservation Check:** PRESERVED ✓
     698
     699---
     700
     701==== 2NF Relation 18: Build
     702
     703Build(build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved)
     704PK: build_id
     705FK: build_user_id → Users.user_id
     706
     707**Derived From:** FD18 (build_id → build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved)
     708
     709**Functional Dependency Enforced:** FD18
     710
     711**Lossless Join Check:**
     712- build_id was part of the composite key in Universal_Relation_1NF
     713- Now build_id becomes the sole primary key in Build
     714- Intersection: I = {build_id}
     715- FD18 guarantees all non-key attributes are uniquely determined by build_id
     716- Join Build ⋈ Universal_Relation_1NF on build_id is lossless
     717- **Result: LOSSLESS ✓**
     718
     719**Dependency Preservation Check:**
     720- FD18: build_id → build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
     721  - All attributes present in Build ✓
     722  - Directly enforceable
     723- **Result: PRESERVED ✓**
     724
     725---
     726
     727==== 2NF Relation 19: Build_Component
     728
     729Build_Component(build_id, component_id, build_component_num_components)
     730PK: (build_id, component_id)
     731FK: build_id → Build.build_id
     732FK: component_id → Components.component_id
     733
     734**Derived From:** FD19 ((build_id, component_id) → build_component_num_components)
     735
     736**Functional Dependency Enforced:** FD19
     737
     738**Lossless Join Check:**
     739- (build_id, component_id) is NOT a proper subset; it equals the original combination for this FD
     740- The composite key becomes the primary key of Build_Component
     741- Intersection: I = {build_id, component_id}
     742- FD19 guarantees the composite key determines the non-key attribute
     743- Join with Universal_Relation_1NF on (build_id, component_id) is lossless
     744- **Result: LOSSLESS ✓**
     745
     746**Dependency Preservation Check:**
     747- FD19: (build_id, component_id) → build_component_num_components
     748  - All attributes present ✓
     749  - Directly enforceable
     750- **Result: PRESERVED ✓**
     751
     752---
     753
     754==== 2NF Relation 20: Rating_Build
     755
     756Rating_Build(build_id, user_id, rating_build_value)
     757PK: (build_id, user_id)
     758FK: build_id → Build.build_id
     759FK: user_id → Users.user_id
     760
     761**Derived From:** FD20 ((build_id, user_id) → rating_build_value)
     762
     763**Functional Dependency Enforced:** FD20
     764
     765**Lossless Join Check:**
     766- (build_id, user_id) is NOT a proper subset of the original composite key
     767- The composite key becomes the primary key of Rating_Build
     768- Intersection: I = {build_id, user_id}
     769- FD20 guarantees the composite key determines the non-key attribute
     770- Join with Universal_Relation_1NF on (build_id, user_id) is lossless
     771- **Result: LOSSLESS ✓**
     772
     773**Dependency Preservation Check:**
     774- FD20: (build_id, user_id) → rating_build_value
     775  - All attributes present ✓
     776  - Directly enforceable
     777- **Result: PRESERVED ✓**
     778
     779---
     780
     781==== 2NF Relation 21: Favorite_Build
     782
     783Favorite_Build(build_id, user_id)
     784PK: (build_id, user_id)
     785FK: build_id → Build.build_id
     786FK: user_id → Users.user_id
     787
     788**Derived From:** FD21 ((build_id, user_id) → ∅)
     789
     790**Functional Dependency Enforced:** FD21
     791
     792**Lossless Join Check:**
     793- (build_id, user_id) forms the complete schema of Favorite_Build
     794- Intersection: I = {build_id, user_id}
     795- The composite key captures the entire relationship
     796- Join with Universal_Relation_1NF on (build_id, user_id) is lossless
     797- **Result: LOSSLESS ✓**
     798
     799**Dependency Preservation Check:**
     800- FD21: (build_id, user_id) → ∅
     801  - The relationship-only FD is preserved through the composite key structure ✓
     802  - Determinant present as primary key
     803- **Result: PRESERVED ✓**
     804
     805---
     806
     807==== 2NF Relation 22: Review
     808
     809Review(review_id, review_build_id, review_user_id, review_content, review_created_at)
     810PK: review_id
     811Alt Key: (review_build_id, review_user_id)
     812FK: review_build_id → Build.build_id
     813FK: review_user_id → Users.user_id
     814
     815**Derived From:** FD22 (review_id → review_build_id, review_user_id, review_content, review_created_at)
     816
     817**Functional Dependency Enforced:** FD22
     818
     819**Lossless Join Check:**
     820- review_id was part of the composite key in Universal_Relation_1NF
     821- Now review_id becomes the sole primary key in Review
     822- Intersection: I = {review_id}
     823- FD22 guarantees review_id uniquely determines all non-key attributes
     824- Join with Universal_Relation_1NF on review_id is lossless
     825- **Result: LOSSLESS ✓**
     826
     827**Dependency Preservation Check:**
     828- FD22: review_id → review_build_id, review_user_id, review_content, review_created_at
     829  - All attributes present in Review ✓
     830  - Directly enforceable
     831- **Result: PRESERVED ✓**
     832
     833---
     834
     835==== 2NF Relation 23: Suggestions
     836
     837Suggestions(suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
     838PK: suggestion_id
     839FK: suggestion_user_id → Users.user_id
     840FK: suggestion_admin_id → Admins.admin_user_id
     841
     842**Derived From:** FD23 (suggestion_id → suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
     843
     844**Functional Dependency Enforced:** FD23
     845
     846**Lossless Join Check:**
     847- suggestion_id was part of the composite key in Universal_Relation_1NF
     848- Now suggestion_id becomes the sole primary key in Suggestions
     849- Intersection: I = {suggestion_id}
     850- FD23 guarantees suggestion_id uniquely determines all non-key attributes
     851- Join with Universal_Relation_1NF on suggestion_id is lossless
     852- **Result: LOSSLESS ✓**
     853
     854**Dependency Preservation Check:**
     855- FD23: suggestion_id → suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     856  - All attributes present ✓
     857  - Directly enforceable
     858- **Result: PRESERVED ✓**
     859
     860---
     861
     862=== 5.3 1NF Multivalued Relations – Already in 2NF
     863
     864The four relations decomposed in the 1NF step (R1–R4: Case_Storage_Form_Factors, Case_Ps_Form_Factors, Case_Mobo_Form_Factors, Cooler_Cpu_Sockets) are already in 2NF because they contain only primary key attributes or attributes fully determined by their composite keys. No further decomposition is required.
     865
     866==== Relation R1: Case_Storage_Form_Factors
     867
     868Case_Storage_Form_Factors(component_id, pc_case_storage_form_factor, pc_case_storage_num_slots)
     869PK: (component_id, pc_case_storage_form_factor)
     870FK: component_id → Components.component_id
     871
     872**2NF Status:** IN 2NF ✓
     873- Composite primary key (component_id, pc_case_storage_form_factor)
     874- The only non-key attribute pc_case_storage_num_slots depends on the entire composite key
     875- No partial dependencies exist
     876
     877**Lossless Join Check:**
     878- Preserved from 1NF decomposition
     879- Already verified as lossless in 1NF section
     880- **Result: LOSSLESS ✓**
     881
     882**Dependency Preservation Check:**
     883- FD24: (component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots
     884  - All attributes present ✓
     885  - Already verified as preserved in 1NF section
     886- **Result: PRESERVED ✓**
     887
     888---
     889
     890==== Relation R2: Case_Ps_Form_Factors
     891
     892Case_Ps_Form_Factors(component_id, pc_case_ps_form_factor)
     893PK: (component_id, pc_case_ps_form_factor)
     894FK: component_id → Components.component_id
     895
     896**2NF Status:** IN 2NF ✓
     897- Only key attributes; no non-key attributes to form partial dependencies
     898
     899**Lossless Join Check:** LOSSLESS ✓ (preserved from 1NF)
     900
     901**Dependency Preservation Check:** PRESERVED ✓ (FD26 preserved in 1NF)
     902
     903---
     904
     905==== Relation R3: Case_Mobo_Form_Factors
     906
     907Case_Mobo_Form_Factors(component_id, pc_case_mobo_form_factor)
     908PK: (component_id, pc_case_mobo_form_factor)
     909FK: component_id → Components.component_id
     910
     911**2NF Status:** IN 2NF ✓
     912- Only key attributes
     913
     914**Lossless Join Check:** LOSSLESS ✓ (preserved from 1NF)
     915
     916**Dependency Preservation Check:** PRESERVED ✓ (FD25 preserved in 1NF)
     917
     918---
     919
     920==== Relation R4: Cooler_Cpu_Sockets
     921
     922Cooler_Cpu_Sockets(component_id, cooler_cpu_socket)
     923PK: (component_id, cooler_cpu_socket)
     924FK: component_id → Components.component_id
     925
     926**2NF Status:** IN 2NF ✓
     927- Only key attributes
     928
     929**Lossless Join Check:** LOSSLESS ✓ (preserved from 1NF)
     930
     931**Dependency Preservation Check:** PRESERVED ✓ (FD27 preserved in 1NF)
     932
     933---
     934
     935== 6. Third Normal Form (3NF) Analysis
     936
     937=== 6.1 Transitive Dependency Analysis for Each 2NF Relation
     938
     939==== Relation 1: Users
     940
     941Users(user_id, username, password, email)
     942PK: user_id
     943FD: FD1 (user_id → username, password, email)
     944
     945**Non-key Attributes:** username, password, email
     946
     947**Transitive Dependency Check:**
     948- Direct dependencies exist:
     949  - user_id → username (direct, via FD1)
     950  - user_id → password (direct, via FD1)
     951  - user_id → email (direct, via FD1)
     952- Potential transitive chains: None
     953  - username does not determine any attribute
     954  - password does not determine any attribute
     955  - email does not determine any attribute
     956
     957**Conclusion:** **NO transitive dependencies exist** ✓
     958- All non-key attributes depend directly on the primary key
     959- **3NF Status: IN 3NF** ✓
     960
     961---
     962
     963==== Relation 2: Admins
     964
     965Admins(admin_user_id, user_id)
     966PK: admin_user_id
     967FD: FD2 (admin_user_id → ∅)
     968
     969**Non-key Attributes:** user_id
     970
     971**Transitive Dependency Check:**
     972- user_id is a **foreign key** (reference to Users.user_id)
     973- Foreign keys are not derived attributes; they are stored references to another table
     974- No chain exists because:
     975  - user_id is not functionally determined by any intermediate non-key attribute
     976  - user_id is directly stored in the relation as a reference
     977  - No further attributes depend on user_id within this relation
     978
     979**Conclusion:** **NO transitive dependencies exist** ✓
     980- Foreign keys do not participate in transitive dependencies (they are direct references, not derived values)
     981- **3NF Status: IN 3NF** ✓
     982
     983---
     984
     985==== Relation 3: Components
     986
     987Components(component_id, component_name, component_brand, component_price, component_type, component_img_url)
     988PK: component_id
     989FD: FD3 (component_id → component_name, component_brand, component_price, component_type, component_img_url)
     990
     991**Non-key Attributes:** component_name, component_brand, component_price, component_type, component_img_url
     992
     993**Transitive Dependency Check:**
     994- All non-key attributes depend directly on component_id:
     995  - component_id → component_name (direct)
     996  - component_id → component_brand (direct)
     997  - component_id → component_price (direct)
     998  - component_id → component_type (direct)
     999  - component_id → component_img_url (direct)
     1000- No attribute depends on another non-key attribute
     1001
     1002**Conclusion:** **NO transitive dependencies exist** ✓
     1003- All attributes are directly determined by the primary key
     1004- No chains of the form PK → B → A exist
     1005- **3NF Status: IN 3NF** ✓
     1006
     1007---
     1008
     1009==== Relation 4: Cpu
     1010
     1011Cpu(component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp)
     1012PK: component_id
     1013FD: FD4 (component_id → cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp)
     1014
     1015**Non-key Attributes:** cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp
     1016
     1017**Transitive Dependency Check:**
     1018- All non-key attributes depend directly on component_id
     1019- No non-key attribute determines another non-key attribute
     1020
     1021**Conclusion:** **NO transitive dependencies exist** ✓
     1022- **3NF Status: IN 3NF** ✓
     1023
     1024---
     1025
     1026==== Relation 5–17: Gpu, Memory, Storage, Power_Supply, Motherboard, Pc_Case, Cooler, Memory_Card, Optical_Drive, Sound_Card, Cables, Network_Adapter, Network_Card
     1027
     1028All 13 of these relations follow the identical pattern:
     1029
     1030**Pattern:**
     1031```
     1032Relation(component_id, [component_specific_attributes])
     1033PK: component_id
     1034FD: component_id → [all dependent attributes]
     1035```
     1036
     1037**Transitive Dependency Check (for each):**
     1038- All non-key attributes depend directly on component_id
     1039- No attribute depends on another non-key attribute
     1040- No chains of the form PK → B → A exist
     1041
     1042**Conclusion for Relations 5–17:** **NO transitive dependencies exist** ✓
     1043- **3NF Status: ALL IN 3NF** ✓
     1044
     1045---
     1046
     1047==== Relation 18: Build
     1048
     1049Build(build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved)
     1050PK: build_id
     1051FD: FD18 (build_id → build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved)
     1052
     1053**Non-key Attributes:** build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved
     1054
     1055**Transitive Dependency Check:**
     1056- Direct dependencies:
     1057  - build_id → build_user_id (direct)
     1058  - build_id → build_name (direct)
     1059  - build_id → build_created_at (direct)
     1060  - build_id → build_description (direct)
     1061  - build_id → build_total_price (direct)
     1062  - build_id → build_is_approved (direct)
     1063- build_user_id is a **foreign key reference** (not derived)
     1064- No non-key attribute determines another non-key attribute
     1065- No chains exist:
     1066  - build_user_id does not determine build_name, build_created_at, etc.
     1067  - Each attribute stands independently, directly determined by build_id
     1068
     1069**Conclusion:** **NO transitive dependencies exist** ✓
     1070- All attributes depend directly on the primary key
     1071- Foreign key does not create transitive dependencies
     1072- **3NF Status: IN 3NF** ✓
     1073
     1074---
     1075
     1076==== Relation 19: Build_Component
     1077
     1078Build_Component(build_id, component_id, build_component_num_components)
     1079PK: (build_id, component_id)
     1080FD: FD19 ((build_id, component_id) → build_component_num_components)
     1081
     1082**Non-key Attributes:** build_component_num_components
     1083
     1084**Transitive Dependency Check:**
     1085- Only one non-key attribute exists: build_component_num_components
     1086- It depends directly on the composite primary key (build_id, component_id)
     1087
     1088**Conclusion:** **NO transitive dependencies exist** ✓
     1089- Only one non-key attribute present
     1090- Direct dependency on composite PK
     1091- **3NF Status: IN 3NF** ✓
     1092
     1093---
     1094
     1095==== Relation 20: Rating_Build
     1096
     1097Rating_Build(build_id, user_id, rating_build_value)
     1098PK: (build_id, user_id)
     1099FD: FD20 ((build_id, user_id) → rating_build_value)
     1100
     1101**Non-key Attributes:** rating_build_value
     1102
     1103**Transitive Dependency Check:**
     1104- Only one non-key attribute: rating_build_value
     1105- Depends directly on (build_id, user_id)
     1106
     1107**Conclusion:** **NO transitive dependencies exist** ✓
     1108- Single non-key attribute
     1109- **3NF Status: IN 3NF** ✓
     1110
     1111---
     1112
     1113==== Relation 21: Favorite_Build
     1114
     1115Favorite_Build(build_id, user_id)
     1116PK: (build_id, user_id)
     1117FD: FD21 ((build_id, user_id) → ∅)
     1118
     1119**Non-key Attributes:** (none)
     1120
     1121**Transitive Dependency Check:**
     1122- No non-key attributes exist
     1123- Therefore, no transitive dependencies can occur
     1124
     1125**Conclusion:** **NO transitive dependencies exist** ✓
     1126- **3NF Status: IN 3NF** ✓
     1127
     1128---
     1129
     1130==== Relation 22: Review
     1131
     1132Review(review_id, review_build_id, review_user_id, review_content, review_created_at)
     1133PK: review_id
     1134Alt Key: (review_build_id, review_user_id)
     1135FD: FD22 (review_id → review_build_id, review_user_id, review_content, review_created_at)
     1136
     1137**Non-key Attributes:** review_build_id, review_user_id, review_content, review_created_at
     1138
     1139**Transitive Dependency Check:**
     1140- Direct dependencies on review_id:
     1141  - review_id → review_build_id (direct, foreign key reference)
     1142  - review_id → review_user_id (direct, foreign key reference)
     1143  - review_id → review_content (direct)
     1144  - review_id → review_created_at (direct)
     1145- review_build_id and review_user_id are foreign keys (not derived)
     1146- No non-key attribute determines another non-key attribute:
     1147  - review_build_id does not determine review_content or review_created_at
     1148  - review_user_id does not determine review_content or review_created_at
     1149  - review_content does not determine review_created_at
     1150
     1151**Conclusion:** **NO transitive dependencies exist** ✓
     1152- All attributes depend directly on review_id
     1153- Foreign keys do not create transitive dependencies
     1154- **3NF Status: IN 3NF** ✓
     1155
     1156---
     1157
     1158==== Relation 23: Suggestions
     1159
     1160Suggestions(suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
     1161PK: suggestion_id
     1162FD: FD23 (suggestion_id → suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
     1163
     1164**Non-key Attributes:** suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type
     1165
     1166**Transitive Dependency Check:**
     1167- All non-key attributes depend directly on suggestion_id:
     1168  - suggestion_id → suggestion_user_id (direct, foreign key)
     1169  - suggestion_id → suggestion_admin_id (direct, foreign key)
     1170  - suggestion_id → suggestion_link (direct)
     1171  - suggestion_id → suggestion_admin_comment (direct)
     1172  - suggestion_id → suggestion_description (direct)
     1173  - suggestion_id → suggestion_status (direct)
     1174  - suggestion_id → suggestion_component_type (direct)
     1175- No non-key attribute determines another non-key attribute
     1176- No chains of form PK → B → A exist
     1177
     1178**Conclusion:** **NO transitive dependencies exist** ✓
     1179- All attributes depend directly on the primary key
     1180- Foreign keys are not derived values
     1181- **3NF Status: IN 3NF** ✓
     1182
     1183---
     1184
     1185==== Relation 24: Case_Storage_Form_Factors
     1186
     1187Case_Storage_Form_Factors(component_id, pc_case_storage_form_factor, pc_case_storage_num_slots)
     1188PK: (component_id, pc_case_storage_form_factor)
     1189FD: FD24 ((component_id, pc_case_storage_form_factor) → pc_case_storage_num_slots)
     1190
     1191**Non-key Attributes:** pc_case_storage_num_slots
     1192
     1193**Transitive Dependency Check:**
     1194- Only one non-key attribute: pc_case_storage_num_slots
     1195- Depends directly on composite PK (component_id, pc_case_storage_form_factor)
     1196
     1197**Conclusion:** **NO transitive dependencies exist** ✓
     1198- **3NF Status: IN 3NF** ✓
     1199
     1200---
     1201
     1202==== Relations 25–27: Case_Ps_Form_Factors, Case_Mobo_Form_Factors, Cooler_Cpu_Sockets
     1203
     1204All three relations follow the identical pattern:
     1205
     1206**Pattern:**
     1207```
     1208Relation(component_id, [attribute])
     1209PK: (component_id, [attribute])
     1210FD: ([attributes] → ∅)
     1211```
     1212
     1213**Transitive Dependency Check (for each):**
     1214- No non-key attributes exist
     1215- Therefore, no transitive dependencies can occur
     1216
     1217**Conclusion for Relations 25–27:** **NO transitive dependencies exist** ✓
     1218- **3NF Status: ALL IN 3NF**
     1219
     1220|| Relation =||= PK Type =||= Non-Key Attributes =||= Transitive Dependency? =||= 3NF Status =||
     1221|| Users || Single (user_id) || 3 attributes || NO || ✓ IN 3NF ||
     1222|| Admins || Single (admin_user_id) || 1 FK || NO || ✓ IN 3NF ||
     1223|| Components || Single (component_id) || 5 attributes || NO || ✓ IN 3NF ||
     1224|| Cpu–Network_Card (14 relations) || Single (component_id) || Variable || NO || ✓ IN 3NF ||
     1225|| Build || Single (build_id) || 6 attributes || NO || ✓ IN 3NF ||
     1226|| Build_Component || Composite || 1 attribute || NO || ✓ IN 3NF ||
     1227|| Rating_Build || Composite || 1 attribute || NO || ✓ IN 3NF ||
     1228|| Favorite_Build || Composite || 0 attributes || NO || ✓ IN 3NF ||
     1229|| Review || Single (review_id) || 4 attributes || NO || ✓ IN 3NF ||
     1230|| Suggestions || Single (suggestion_id) || 7 attributes || NO || ✓ IN 3NF ||
     1231|| Case_Storage_Form_Factors || Composite || 1 attribute || NO || ✓ IN 3NF ||
     1232|| Case_Ps_Form_Factors || Composite || 0 attributes || NO || ✓ IN 3NF ||
     1233|| Case_Mobo_Form_Factors || Composite || 0 attributes || NO || ✓ IN 3NF ||
     1234|| Cooler_Cpu_Sockets || Composite || 0 attributes || NO || ✓ IN 3NF ||
     1235
     1236== 6. Final BCNF Decomposed Schema
     1237
     1238=== 6.1 Complete List of All Relations
     1239
     12401. **Users**(user_id, username, password, email)
     1241   - PK: user_id
     1242
     12432. **Admins**(admin_user_id)
     1244   - PK: admin_user_id
     1245   - FK: admin_user_id → Users.user_id
     1246
     12473. **Components**(component_id, component_name, component_brand, component_price, component_type, component_img_url)
     1248   - PK: component_id
     1249
     12504. **Cpu**(component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp)
     1251   - PK: component_id
     1252   - FK: component_id → Components.component_id
     1253
     12545. **Gpu**(component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length)
     1255   - PK: component_id
     1256   - FK: component_id → Components.component_id
     1257
     12586. **Memory**(component_id, memory_type, memory_speed, memory_capacity, memory_modules)
     1259   - PK: component_id
     1260   - FK: component_id → Components.component_id
     1261
     12627. **Storage**(component_id, storage_type, storage_capacity, storage_form_factor)
     1263   - PK: component_id
     1264   - FK: component_id → Components.component_id
     1265
     12668. **Power_Supply**(component_id, power_supply_type, power_supply_wattage, power_supply_form_factor)
     1267   - PK: component_id
     1268   - FK: component_id → Components.component_id
     1269
     12709. **Motherboard**(component_id, motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots)
     1271   - PK: component_id
     1272   - FK: component_id → Components.component_id
     1273
     127410. **Pc_Case**(component_id, pc_case_cooler_max_height, pc_case_gpu_max_length)
     1275    - PK: component_id
     1276    - FK: component_id → Components.component_id
     1277
     127811. **Cooler**(component_id, cooler_type, cooler_height, cooler_max_tdp_supported)
     1279    - PK: component_id
     1280    - FK: component_id → Components.component_id
     1281
     128212. **Memory_Card**(component_id, memory_card_num_slots, memory_card_interface)
     1283    - PK: component_id
     1284    - FK: component_id → Components.component_id
     1285
     128613. **Optical_Drive**(component_id, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed)
     1287    - PK: component_id
     1288    - FK: component_id → Components.component_id
     1289
     129014. **Sound_Card**(component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel)
     1291    - PK: component_id
     1292    - FK: component_id → Components.component_id
     1293
     129415. **Cables**(component_id, cables_length_cm, cables_type)
     1295    - PK: component_id
     1296    - FK: component_id → Components.component_id
     1297
     129816. **Network_Adapter**(component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas)
     1299    - PK: component_id
     1300    - FK: component_id → Components.component_id
     1301
     130217. **Network_Card**(component_id, network_card_num_ports, network_card_speed, network_card_interface)
     1303    - PK: component_id
     1304    - FK: component_id → Components.component_id
     1305
     130618. **Build**(build_id, build_user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved)
     1307    - PK: build_id
     1308    - FK: build_user_id → Users.user_id
     1309
     131019. **Build_Component**(build_id, component_id, build_component_num_components)
     1311    - PK: (build_id, component_id)
     1312    - FK: build_id → Build.build_id
     1313    - FK: component_id → Components.component_id
     1314
     131520. **Rating_Build**(build_id, user_id, rating_build_value)
     1316    - PK: (build_id, user_id)
     1317    - FK: build_id → Build.build_id
     1318    - FK: user_id → Users.user_id
     1319
     132021. **Favorite_Build**(build_id, user_id)
     1321    - PK: (build_id, user_id)
     1322    - FK: build_id → Build.build_id
     1323    - FK: user_id → Users.user_id
     1324
     132522. **Review**(review_id, review_build_id, review_user_id, review_content, review_created_at)
     1326    - PK: review_id
     1327    - Alt Key: (review_build_id, review_user_id)
     1328    - FK: review_build_id → Build.build_id
     1329    - FK: review_user_id → Users.user_id
     1330
     133123. **Suggestions**(suggestion_id, suggestion_user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type)
     1332    - PK: suggestion_id
     1333    - FK: suggestion_user_id → Users.user_id
     1334    - FK: suggestion_admin_id → Admins.admin_user_id
     1335
     133624. **Case_Storage_Form_Factors**(component_id, pc_case_storage_form_factor, pc_case_storage_num_slots)
     1337    - PK: (component_id, pc_case_storage_form_factor)
     1338    - FK: component_id → Components.component_id
     1339
     134025. **Case_Ps_Form_Factors**(component_id, pc_case_ps_form_factor)
     1341    - PK: (component_id, pc_case_ps_form_factor)
     1342    - FK: component_id → Components.component_id
     1343
     134426. **Case_Mobo_Form_Factors**(component_id, pc_case_mobo_form_factor)
     1345    - PK: (component_id, pc_case_mobo_form_factor)
     1346    - FK: component_id → Components.component_id
     1347
     134827. **Cooler_Cpu_Sockets**(component_id, cooler_cpu_socket)
     1349    - PK: (component_id, cooler_cpu_socket)
     1350    - FK: component_id → Components.component_id
     1351
     1352