| 2 | | |
| 3 | | == Initial de-normalized relation (R) and functional dependencies |
| 4 | | |
| 5 | | R( |
| 6 | | user_id, username, password, email, |
| 7 | | component_id, component_name, brand, price, component_type, img_url, |
| 8 | | cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, |
| 9 | | gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length, |
| 10 | | memory_type, memory_speed, memory_capacity, memory_modules, |
| 11 | | storage_type, storage_capacity, storage_form_factor, |
| 12 | | psu_type, psu_wattage, psu_form_factor, |
| 13 | | motherboard_socket, motherboard_chipset, motherboard_form_factor, |
| 14 | | ram_type, num_ram_slots, max_ram_capacity, pci_express_slots, |
| 15 | | case_cooler_max_height, case_gpu_max_length, |
| 16 | | case_storage_form_factor, case_storage_slots, |
| 17 | | case_ps_form_factor, |
| 18 | | case_mobo_form_factor, |
| 19 | | cooler_type, cooler_height, cooler_max_tdp, |
| 20 | | cooler_socket, |
| 21 | | memory_card_slots, memory_card_interface, |
| 22 | | optical_form_factor, optical_type, optical_interface, |
| 23 | | optical_write_speed, optical_read_speed, |
| 24 | | sound_sample_rate, sound_bit_depth, sound_chipset, sound_interface, sound_channel, |
| 25 | | cable_length, cable_type, |
| 26 | | net_adapter_wifi, net_adapter_interface, net_adapter_antennas, |
| 27 | | net_card_ports, net_card_speed, net_card_interface, |
| 28 | | build_id, build_name, build_created_at, build_description, |
| 29 | | build_total_price, build_is_approved, |
| 30 | | build_component_id, |
| 31 | | rating_value, review_content, review_created_at, |
| 32 | | suggestion_id, suggestion_link, suggestion_description, |
| 33 | | suggestion_status, suggestion_admin_comment, suggestion_component_type |
| 34 | | ) |
| 35 | | |
| 36 | | Functional dependencies: |
| 37 | | |
| 38 | | user_id → username, password, email |
| 39 | | |
| 40 | | component_id → name, brand, price, component_type, img_url |
| 41 | | |
| 42 | | component_id → cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp |
| 43 | | |
| 44 | | component_id → gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length |
| 45 | | |
| 46 | | component_id → memory_type, memory_speed, memory_capacity, memory_modules |
| 47 | | |
| 48 | | component_id → storage_type, storage_capacity, storage_form_factor |
| 49 | | |
| 50 | | component_id → psu_type, psu_wattage, psu_form_factor |
| 51 | | |
| 52 | | component_id → motherboard_socket, motherboard_chipset, motherboard_form_factor, ram_type, num_ram_slots, max_ram_capacity, pci_express_slots |
| 53 | | |
| 54 | | component_id → case_cooler_max_height, case_gpu_max_length |
| 55 | | |
| 56 | | component_id → cooler_type, cooler_height, cooler_max_tdp |
| 57 | | |
| 58 | | component_id → memory_card_slots, memory_card_interface |
| 59 | | |
| 60 | | component_id → optical_form_factor, optical_type, optical_interface, optical_write_speed, optical_read_speed |
| 61 | | |
| 62 | | component_id → sound_sample_rate, sound_bit_depth, sound_chipset, sound_interface, sound_channel |
| 63 | | |
| 64 | | component_id → cable_length, cable_type |
| 65 | | |
| 66 | | component_id → net_adapter_wifi, net_adapter_interface, net_adapter_antennas |
| 67 | | |
| 68 | | component_id → net_card_ports, net_card_speed, net_card_interface |
| 69 | | |
| 70 | | (component_id, form_factor) → /, for case motherboard and power supply form factors |
| 71 | | |
| 72 | | (component_id, form_factor) → num_slots, for case storage form factors |
| 73 | | |
| 74 | | (component_id, socket) → /, for cooler cpu sockets |
| 75 | | |
| 76 | | build_id → user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved |
| 77 | | |
| 78 | | build_component_id → build_id, user_id |
| 79 | | |
| 80 | | (build_id, user_id) → rating_value |
| 81 | | |
| 82 | | review_id → build_id, user_id, review_content, review_created_at |
| 83 | | |
| 84 | | suggestion_id → user_id, admin_id, link, description, status, admin_comment, component_type |
| 85 | | |
| 86 | | The de-normalized relation violates 1NF because it contains multi-valued attributes. |
| 87 | | |
| 88 | | == Candidate keys of the de-normalized relation |
| 89 | | |
| 90 | | Because the universal relation combines users, builds, components, reviews, and suggestions, a minimal key must uniquely identify all of them. |
| 91 | | |
| 92 | | The artifical candidate key is {user_id, build_id, component_id, review_id, suggestion_id, build_component_id} |
| 93 | | |
| 94 | | Universal relation primary key = {user_id, build_id, component_id, review_id, suggestion_id, build_component_id} |
| | 2 | == Initial de-normalized relation and functional dependencies |
| | 3 | 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. |
| | 4 | |
| | 5 | R(user_id, username, password, email, |
| | 6 | component_id, component_name, brand, component_price, component_type, |
| | 7 | cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, |
| | 8 | gpu_vram, gpu_tdp, gpu_base_clock, gpu¬_boost_clock, gpu_chipset, gpu_length, |
| | 9 | memory_type, memory_speed, memory_capacity, memory_modules, |
| | 10 | storage_type, storage_capacity, storage_form_factor, |
| | 11 | power_supply_type, power_supply_capacity, power_supply_form_factor, |
| | 12 | motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots, |
| | 13 | pc_case_coooler_max_height, pc_case_gpu_max_length, |
| | 14 | pc_case_storage_form_factor, num_slots |
| | 15 | pc_case_ps_form_factor, |
| | 16 | pc_case_mobo_form_factor, |
| | 17 | cooler_type, cooler_height, cooler_max_tdp_supported, |
| | 18 | cooler_cpu_socket, |
| | 19 | memory_card_num_slots, memory_card_interface, |
| | 20 | optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed, |
| | 21 | sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel, |
| | 22 | cables_length_cm, cables_type, |
| | 23 | network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas, |
| | 24 | network_card_num_ports, network_card_speed, network_card_interface, |
| | 25 | build_id, build_name, build_created_at, build_description, build_total_price, build_is_approved, |
| | 26 | num_components, |
| | 27 | rating_build_value, |
| | 28 | review_id, review_content, review_created_at, |
| | 29 | suggestion_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type |
| | 30 | |
| | 31 | Before anything else, we need to note that pc_case_storage_form_factor (composite attribute with num_slots), pc_case_ps_form_factor, pc_case_mobo_form_factor and cooler_cpu_socket are multivalued attributes. |
| | 32 | |
| | 33 | 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. |
| | 34 | |
| | 35 | FD1: user_id -> username, password, email |
| | 36 | |
| | 37 | FD2: component_id -> component_name, brand, component_price, component_type, img_url |
| | 38 | |
| | 39 | FD3: component_id(cpu) -> cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp |
| | 40 | |
| | 41 | FD4: component_id(gpu) -> gpu_vram, gpu_tdp, gpu_base_clock, gpu¬_boost_clock, gpu_chipset, gpu_length |
| | 42 | |
| | 43 | FD5: component_id(memory) -> memory_type, memory_speed, memory_capacity, memory_modules |
| | 44 | |
| | 45 | FD6: component_id(storage) -> storage_type, storage_capacity, storage_form_factor |
| | 46 | |
| | 47 | FD7: component_id (power_supply) -> power_supply_type, power_supply_capacity, power_supply_form_factor |
| | 48 | |
| | 49 | FD8: 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 |
| | 50 | |
| | 51 | FD9: component_id(pc_case) -> pc_case_coooler_max_height, pc_case_gpu_max_length |
| | 52 | |
| | 53 | FD10: component_id(cooler) -> cooler_type, cooler_height, cooler_max_tdp_supported |
| | 54 | |
| | 55 | FD11: component_id(memory_card) -> memory_card_num_slots, memory_card_interface |
| | 56 | |
| | 57 | FD12: component_id(optical_drive) -> optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed |
| | 58 | |
| | 59 | FD13: component_id(sound_card) -> sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel |
| | 60 | |
| | 61 | FD14: component_id(cables) -> cables_length_cm, cables_type |
| | 62 | |
| | 63 | FD15: component_id(network_adapter) -> network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas |
| | 64 | |
| | 65 | FD16: component_id(network_card) -> network_card_num_ports, network_card_speed, network_card_interface |
| | 66 | |
| | 67 | FD17: build_id -> user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved |
| | 68 | |
| | 69 | FD18: build_id, component_id -> num_components |
| | 70 | |
| | 71 | FD19: build_id, user_id -> / |
| | 72 | |
| | 73 | FD20: build_id, user_id -> rating_build_value |
| | 74 | |
| | 75 | FD21: review_id -> build_id, user_id, review_content, review_created_at |
| | 76 | |
| | 77 | FD22: suggestion_id -> user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type |
| | 78 | |
| | 79 | Left: user_id, component_id, build_id, review_id, suggestion_id |
| | 80 | |
| | 81 | Left and right: build_id, user_id |
| | 82 | |
| | 83 | Right: |
| | 84 | username, password, email, component_name, brand, component_price, component_type, 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_capacity, 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_coooler_max_height, pc_case_gpu_max_length, num_slots, pc_case_storage_form_factor, pc_case_ps_form_factor, pc_case_mobo_form_factor, cooler_cpu_socket, 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, build_name, build_created_at, build_description, build_total_price, build_is_approved, rating_build_value, review_content, review_created_at, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type |
| | 85 | |
| | 86 | Attributes that never appear on the right side(only left) are component_id, review_id, suggestion_id. This means that they must be a part of the candidate key because nothing else can determine them. |
| | 87 | |
| | 88 | Let K = { component_id, review_id, suggestion_id } |
| | 89 | |
| | 90 | We now compute the closure K+ |
| | 91 | |
| | 92 | Start with K+ = { component_id, review_id, suggestion_id } |
| | 93 | |
| | 94 | By applying FD2 – FD16, we add: |
| | 95 | component_name, brand, component_price, component_type, |
| | 96 | cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp, |
| | 97 | gpu_vram, gpu_tdp, gpu_base_clock, gpu¬_boost_clock, gpu_chipset, gpu_length, |
| | 98 | memory_type, memory_speed, memory_capacity, memory_modules, |
| | 99 | storage_type, storage_capacity, storage_form_factor, |
| | 100 | power_supply_type, power_supply_capacity, power_supply_form_factor, |
| | 101 | motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, motherboard_pci_express_slots, |
| | 102 | pc_case_coooler_max_height, pc_case_gpu_max_length, |
| | 103 | cooler_type, cooler_height, cooler_max_tdp_supported, |
| | 104 | memory_card_num_slots, memory_card_interface, |
| | 105 | optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed, |
| | 106 | sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel, |
| | 107 | cables_length_cm, cables_type, |
| | 108 | network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas, |
| | 109 | network_card_num_ports, network_card_speed, network_card_interface |
| | 110 | |
| | 111 | By applying FD21, we add: |
| | 112 | build_id, user_id, review_content, review_created_at |
| | 113 | |
| | 114 | By applying FD17, we add: |
| | 115 | build_name, build_created_at, build_description, build_total_price, build_is_approved |
| | 116 | |
| | 117 | By applying FD1, we add: |
| | 118 | username, password, email |
| | 119 | |
| | 120 | By applying FD22, we add: |
| | 121 | suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type |
| | 122 | |
| | 123 | By applying FD18 and FD20, we add: |
| | 124 | num_components, rating_build_value |
| | 125 | |
| | 126 | After excluding multivalued attributes which we handle separatelu in 1NF, K+ contains all attributes of R, which means that K is a superkey. |
| | 127 | |
| | 128 | The universal relation violates 1NF because the attributes case_storage_form_factor, case_ps_form_factor, 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. |
| 97 | | |
| 98 | | Here we have to separate the multi-valued attributes into individual relations. This will ensure that all values are atomic. |
| 99 | | |
| 100 | | case_storage_form_factors(case_id, form_factor, num_slots) |
| 101 | | |
| 102 | | case_ps_form_factors(case_id, form_factor) |
| 103 | | |
| 104 | | case_mobo_form_factors(case_id, form_factor) |
| 105 | | |
| 106 | | cooler_cpu_sockets(cooler_id, socket) |
| 107 | | |
| 108 | | |
| 109 | | We separate obvious entities in individual relations: |
| 110 | | |
| 111 | | users(user_id, username, password, email) |
| 112 | | |
| 113 | | admins(user_id) |
| 114 | | |
| 115 | | components(component_id, name, brand, price, component_type, img_url) |
| 116 | | |
| 117 | | cpu(component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp) |
| 118 | | |
| 119 | | gpu(component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length) |
| 120 | | |
| 121 | | memory(component_id, memory_type, memory_speed, memory_capacity, memory_modules) |
| 122 | | |
| 123 | | storage(component_id, storage_type, storage_capacity, storage_form_factor) |
| 124 | | |
| 125 | | power_supply(component_id, psu_type, psu_wattage, psu_form_factor) |
| 126 | | |
| 127 | | motherboard(component_id, motherboard_socket, motherboard_chipset, motherboard_form_factor, ram_type, num_ram_slots, max_ram_capacity, pci_express_slots) |
| 128 | | |
| 129 | | pc_case(component_id, case_cooler_max_height, case_gpu_max_length) |
| 130 | | |
| 131 | | cooler(component_id, cooler_type, cooler_height, cooler_max_tdp) |
| 132 | | |
| 133 | | memory_card(component_id, memory_card_slots, memory_card_interface) |
| 134 | | |
| 135 | | optical_drive(component_id, optical_form_factor, optical_type, optical_interface, optical_write_speed, optical_read_speed) |
| 136 | | |
| 137 | | sound_card(component_id, sound_sample_rate, sound_bit_depth, sound_chipset, sound_interface, sound_channel) |
| 138 | | |
| 139 | | cables(component_id, cable_length, cable_type) |
| 140 | | |
| 141 | | network_adapter(component_id, net_adapter_wifi, net_adapter_interface, net_adapter_antennas) |
| 142 | | |
| 143 | | network_card(component_id, net_card_ports, net_card_speed, net_card_interface) |
| 144 | | |
| 145 | | build(build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved) |
| 146 | | |
| 147 | | build_component(build_component_id, build_id, component_id) |
| 148 | | |
| 149 | | review(review_id, build_id, user_id, review_content, review_created_at) |
| 150 | | |
| 151 | | rating_build(build_id, user_id, rating_value) |
| 152 | | |
| 153 | | suggestions(suggestion_id, user_id, admin_id, link, description, status, admin_comment, component_type) |
| 154 | | |
| 155 | | all of which satisfy 1NF. |
| 156 | | |
| 157 | | |
| 158 | | Candidate keys & primary keys: |
| 159 | | |
| 160 | | users → user_id |
| 161 | | |
| 162 | | admins → user_id |
| 163 | | |
| 164 | | components → component_id |
| 165 | | |
| 166 | | component subclasses (like cpu, gpu etc.) → component_id |
| 167 | | |
| 168 | | build → build_id |
| 169 | | |
| 170 | | build_component → build_component_id |
| 171 | | |
| 172 | | review → review_id |
| 173 | | |
| 174 | | rating_build → (build_id, user_id) |
| 175 | | |
| 176 | | favorite_build → (build_id, user_id) |
| 177 | | |
| 178 | | suggestions → suggestion_id |
| 179 | | |
| 180 | | == Second Normal Form (2NF) |
| 181 | | |
| 182 | | 2NF focuses on partial dependencies, which can only occur when a relation has a composite primary key and a non-key attribute depends on only part of that key. Relations with a single-attribute primary key were considered to be automatically in 2NF. Most of the relations obtained after 1NF like users, components, build, review and suggestions, have single-attribute primary keys so partial dependencies cannot exist in these relations. The remaining relations that have composite primary keys favorite_build and rating_build were analyzed separately. |
| 183 | | |
| 184 | | favorite_build(build_id, user_id) - doesn't have non-key attributes so it is already 2NF |
| 185 | | |
| 186 | | rating_build(build_id, user_id, rating_value) - rating_value depends on full key so it is 2NF |
| 187 | | |
| 188 | | In the case of associative tables like build_component and favorite_build no non-key attributes are present so partial dependencies are not possible. For rating_build the non-key attribute depend on the full composite key (a rating is uniquely determined by both the user and the build). Since no non-key attribute was found to be partially dependent all relations satisfy 2NF. |
| 189 | | |
| 190 | | == Third normal Form (3NF) |
| 191 | | |
| 192 | | users(user_id, username, password, email) - all attributes depend directly on user_id so 3NF is satisfied |
| 193 | | |
| 194 | | components(component_id, name, brand, price, component_type, img_url) - all attributes depend directly on component_id so this is 3NF |
| 195 | | |
| 196 | | build(build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved) - all attributes depend on build_id which means that 3NF is satisfied |
| 197 | | |
| 198 | | component subclasses (like cpu, gpu, memory etc.) - all attributes depend directly on component_id so 3NF is satisfied |
| 199 | | |
| 200 | | review(review_id, build_id, user_id, review_content, review_created_at) - attributes depend on review_id, 3NF is satisfied |
| 201 | | |
| 202 | | rating_build(build_id, user_id, rating_value) → rating_value depends on (build_id, user_id), 3NF is satisfied |
| 203 | | |
| 204 | | favorite_build(build_id, user_id) - no non-key attributes so this automatically satisfies 3NF |
| 205 | | |
| 206 | | suggestions(suggestion_id, user_id, admin_id, link, description, status, admin_comment, component_type) - attributes depend on suggestion_id, 3NF is satisfied |
| 207 | | |
| 208 | | case_storage_form_factors(case_id, form_factor, num_slots) - no transitive dependencies, 3NF is satisfied |
| 209 | | |
| 210 | | case_ps_form_factors(case_id, form_factor) - no transitive dependencies, 3NF is satisfied |
| 211 | | |
| 212 | | case_mobo_form_factors(case_id, form_factor) - no transitive dependencies, 3NF is satisfied |
| 213 | | |
| 214 | | cooler_cpu_sockets(cooler_id, socket) - no transitive dependencies, 3NF is satisfied |
| 215 | | |
| 216 | | build_component(build_component_id, build_id, component_id) - no transitive dependencies because all attributes depend on build_component_id, therefore 3NF is satisfied. |
| 217 | | |
| 218 | | == BCNF decomposition |
| 219 | | |
| 220 | | BCNF checks if every determinant is a super-key so we need to analyze all 3NF relations. |
| 221 | | |
| 222 | | users(user_id, username, password, email): |
| 223 | | |
| 224 | | FD: user_id → username, password, email |
| 225 | | |
| 226 | | Determinant user_id is the primary key (superkey), BCNF |
| 227 | | |
| 228 | | |
| 229 | | admins(user_id): |
| 230 | | |
| 231 | | Determinant user_id is the primary key (superkey), BCNF |
| 232 | | |
| 233 | | |
| 234 | | components(component_id, name, brand, price, component_type, img_url): |
| 235 | | |
| 236 | | FD: component_id → name, brand, price, component_type, img_url |
| 237 | | |
| 238 | | Determinant component_id is the primary key (superkey), BCNF |
| 239 | | |
| 240 | | |
| 241 | | Component specialization tables (cpu, gpu, memory, etc.): |
| 242 | | |
| 243 | | Each table: primary key = component_id |
| 244 | | |
| 245 | | All attributes depend only on component_id |
| 246 | | |
| 247 | | Determinant is primary key(superkey), BCNF |
| 248 | | |
| 249 | | |
| 250 | | build(build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved): |
| 251 | | |
| 252 | | FD: build_id → user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved |
| 253 | | |
| 254 | | Determinant build_id is primary key(superkey), BCNF |
| 255 | | |
| 256 | | |
| 257 | | build_component(build_component_id, build_id, component_id): |
| 258 | | |
| 259 | | FD: build_component_id → build_id, component_id |
| 260 | | |
| 261 | | Determinant build_component_id is primary key(superkey), BCNF |
| 262 | | |
| 263 | | |
| 264 | | favorite_build(build_id, user_id): |
| 265 | | |
| 266 | | FD: Composite key (build_id, user_id) → / |
| 267 | | |
| 268 | | No non-key attributes so its by default BCNF |
| 269 | | |
| 270 | | |
| 271 | | rating_build(build_id, user_id, rating_value): |
| 272 | | |
| 273 | | FD: (build_id, user_id) → rating_value |
| 274 | | |
| 275 | | Determinant is full primary key (superkey), BCNF |
| 276 | | |
| 277 | | |
| 278 | | review(review_id, build_id, user_id, review_content, review_created_at): |
| 279 | | |
| 280 | | FD: review_id → build_id, user_id, review_content, review_created_at |
| 281 | | |
| 282 | | Determinant = primary key (superkey), BCNF |
| 283 | | |
| 284 | | |
| 285 | | suggestions(suggestion_id, user_id, admin_id, link, description, status, admin_comment, component_type): |
| 286 | | |
| 287 | | FD: suggestion_id → user_id, admin_id, link, description, status, admin_comment, component_type |
| 288 | | |
| 289 | | Determinant is primary key (superkey) |
| 290 | | |
| 291 | | |
| 292 | | case_storage_form_factors(case_id, form_factor, num_slots): |
| 293 | | |
| 294 | | FD: (case_id, form_factor) → num_slots |
| 295 | | |
| 296 | | Full composite key is determinant (superkey), BCNF |
| 297 | | |
| 298 | | |
| 299 | | case_ps_form_factors(case_id, form_factor): |
| 300 | | |
| 301 | | FD: (case_id, form_factor) → / |
| 302 | | |
| 303 | | Full composite key is determinant (superkey), BCNF |
| 304 | | |
| 305 | | |
| 306 | | case_mobo_form_factors(case_id, form_factor): |
| 307 | | |
| 308 | | FD: (case_id, form_factor) → / |
| 309 | | |
| 310 | | Full composite key is determinant (superkey), BCNF |
| 311 | | |
| 312 | | |
| 313 | | cooler_cpu_sockets(cooler_id, socket): |
| 314 | | |
| 315 | | FD: (cooler_id, socket) → / |
| 316 | | |
| 317 | | Full composite key is determinant (superkey), BCNF |
| 318 | | |
| 319 | | |
| 320 | | We can now see that all determinants are superkeys, so BCNF is satisfied. |
| 321 | | |
| 322 | | |
| | 131 | To achieve 1NF, we decompose the multivalued attributes from R into: |
| | 132 | |
| | 133 | component_id , pc_case_storage_form_factor -> num_slots |
| | 134 | |
| | 135 | component_id, pc_case_ps_form_factor -> no non-key attributes |
| | 136 | |
| | 137 | component_id, pc_case_mobo_form_factor -> no non-key attributes |
| | 138 | |
| | 139 | component_id, cooler_cpu_socket -> no non-key attributes |
| | 140 | |
| | 141 | 1NF is satisfied now. 2NF is not satisfied because of partial dependencies. We can see this through the functional dependencies: |
| | 142 | |
| | 143 | FD2-FD16: component_id is part of the key, but the these attributes such as component_name, brand, component_price etc. depend only on component_id. |
| | 144 | |
| | 145 | We will decompose by creating new relations from R following FD2 to FD16 where the attributes will depend only on component_id: |
| | 146 | |
| | 147 | component_id -> component_id, component_name, brand, component_price, component_type, img_url |
| | 148 | |
| | 149 | component_id -> cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp |
| | 150 | |
| | 151 | component_id -> gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length |
| | 152 | |
| | 153 | component_id -> memory_type, memory_speed, memory_capacity, memory_modules |
| | 154 | |
| | 155 | component_id -> storage_type, storage_capacity, storage_form_factor |
| | 156 | |
| | 157 | component_id -> power_supply_type, power_supply_capacity, power_supply_form_factor |
| | 158 | |
| | 159 | component_id -> motherboard_socket, motherboard_chipset, motherboard_form_factor, motherboard_ram_type, motherboard_num_ram_slots, motherboard_max_ram_capacity, |
| | 160 | motherboard_pci_express_slots |
| | 161 | |
| | 162 | component_id -> pc_case_coooler_max_height, pc_case_gpu_max_length |
| | 163 | |
| | 164 | component_id -> cooler_type, cooler_height, cooler_max_tdp_supported, cooler_cpu_socket |
| | 165 | |
| | 166 | component_id -> memory_card_num_slots, memory_card_interface |
| | 167 | |
| | 168 | component_id -> optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed |
| | 169 | |
| | 170 | component_id -> sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel |
| | 171 | |
| | 172 | component_id -> cables_length_cm, cables_type |
| | 173 | |
| | 174 | component_id -> network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas |
| | 175 | |
| | 176 | component_id -> network_card_num_ports, network_card_speed, network_card_interface |
| | 177 | |
| | 178 | Primary key in all of these is component_id. |
| | 179 | |
| | 180 | FD21: review_id is part of the key, but these attributes build_id, user_id, review_content, review_created_at depend only on review_id. |
| | 181 | |
| | 182 | We will solve this partial dependency by creating a new relation: |
| | 183 | |
| | 184 | review_id -> build_id, user_id, review_content, review_created_at |
| | 185 | |
| | 186 | Primary key here is review_id. |
| | 187 | |
| | 188 | FD22: suggestion_id is part of the key, but user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type depend only on suggestion_id. |
| | 189 | |
| | 190 | We will solve this partial dependency by creating a new relation: |
| | 191 | |
| | 192 | suggestion_id -> user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type |
| | 193 | |
| | 194 | We get the following relations: |
| | 195 | |
| | 196 | R1 { review_id, build_id, user_id, review_content, review_created_at } where PK = review_id - BCNF |
| | 197 | |
| | 198 | R2 { suggestion_id, user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type } where PK = suggestion_id - BCNF |
| | 199 | |
| | 200 | R3 { component_id, component_name, brand, component_price, component_type, img_url } where PK = component_id - BCNF |
| | 201 | |
| | 202 | R4 { component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp } where PK = component_id - BCNF |
| | 203 | |
| | 204 | R5 { component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length } where PK = component_id - BCNF |
| | 205 | |
| | 206 | R6 { component_id, memory_type, memory_speed, memory_capacity, memory_modules } where PK = component_id - BCNF |
| | 207 | |
| | 208 | R7 { component_id, storage_type, storage_capacity, storage_form_factor } where PK = component_id - BCNF |
| | 209 | |
| | 210 | R8 { component_id, power_supply_type, power_supply_capacity, power_supply_form_factor } where PK = component_id - BCNF |
| | 211 | |
| | 212 | 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 |
| | 213 | |
| | 214 | R10 { component_id, pc_case_coooler_max_height, pc_case_gpu_max_length } where PK = component_id - BCNF |
| | 215 | |
| | 216 | R11 { component_id, cooler_type, cooler_height, cooler_max_tdp_supported, cooler_cpu_socket } where PK = component_id - BCNF |
| | 217 | |
| | 218 | R12 { component_id, memory_card_num_slots, memory_card_interface } where PK = component_id - BCNF |
| | 219 | |
| | 220 | R13 { 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 |
| | 221 | |
| | 222 | R14 { component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel } where PK = component_id - BCNF |
| | 223 | |
| | 224 | R15 { component_id, cables_length_cm, cables_type } where PK = component_id - BCNF |
| | 225 | |
| | 226 | R16 { component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas } where PK = component_id - BCNF |
| | 227 | |
| | 228 | R17 { component_id, network_card_num_ports, network_card_speed, network_card_interface } where PK = component_id - BCNF |
| | 229 | |
| | 230 | R18 { component_id, pc_case_storage_form_factor , num_slots } where PK = component_id and pc_case_storage_form_factor - BCNF |
| | 231 | |
| | 232 | R19 { component_id, pc_case_ps_form_factor } where PK = component_id and pc_case_ps_form_factor - BCNF |
| | 233 | |
| | 234 | R20 { component_id, pc_case_mobo_form_factor } where PK = component_id and pc_case_mobo_form_factor - BCNF |
| | 235 | |
| | 236 | R21 { component_id, cooler_cpu_socket } where PK = component_id and cooler_cpu_socket - BCNF |
| | 237 | |
| | 238 | The remainder of R { component_id, review_id, suggestion_id, build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved, num_components, rating_build_value, username, password, email } where PK = K (component_id, review_id, suggestion_id) |
| | 239 | |
| | 240 | 2NF is satisfied but the remaining of R has transitive dependencies which violate 3NF. When looking at FD17: build_id -> build_name, build_created_at, build_description, build_total_price, build_is_approved, here build_id is not part of the candidate key K, but it determines build_name and other attributes. The same thing goes for user_id -> username, password, email when looking at FD1. We will handle these transitive dependencies by creating separate tables. |
| | 241 | |
| | 242 | == 3NF decomposition |
| | 243 | R22 { user_id, username, password, email } where PK = user_id - BCNF |
| | 244 | |
| | 245 | R23 { build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved } where PK = build_id – BCNF |
| | 246 | |
| | 247 | Leftover relation R { component_id, review_id, suggestion_id, build_id, user_id, num_components, rating_build_value } |
| | 248 | |
| | 249 | From FD18 (build_id, component_id) → num_components we see that build_id and component_id is not a superkey of leftover relation R, this violates BCNF. Same thing goes for FD19 (build_id, user_id) -> / and FD20 (build_id, user_id) → rating_build_value, build_id and user_id is not a superkey of the leftover relation. We will decompose by creating new relations |
| | 250 | |
| | 251 | R24 { build_id , component_id, num_components } where PK = build_id, component_id - BCNF |
| | 252 | |
| | 253 | R25 { build_id, user_id, rating_build_value } where PK = build_id, user_id - BCNF |
| | 254 | |
| | 255 | R26 { build_id, user_id } where PK = build_id, user_id – BCNF |
| | 256 | |
| | 257 | == Final BCNF relations |
| | 258 | |
| | 259 | Users { user_id, username, password, email } |
| | 260 | |
| | 261 | Components { component_id, component_name, brand, component_price, component_type, img_url } |
| | 262 | |
| | 263 | Cpu { component_id, cpu_socket, cpu_cores, cpu_threads, cpu_base_clock, cpu_boost_clock, cpu_tdp } |
| | 264 | |
| | 265 | Gpu { { component_id, gpu_vram, gpu_tdp, gpu_base_clock, gpu_boost_clock, gpu_chipset, gpu_length } |
| | 266 | |
| | 267 | Memory { component_id, memory_type, memory_speed, memory_capacity, memory_modules } |
| | 268 | |
| | 269 | Storage { component_id, storage_type, storage_capacity, storage_form_factor } |
| | 270 | |
| | 271 | Power_Supply { component_id, power_supply_type, power_supply_capacity, power_supply_form_factor } |
| | 272 | |
| | 273 | 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 } |
| | 274 | |
| | 275 | Pc_Case { component_id, pc_case_coooler_max_height, pc_case_gpu_max_length } |
| | 276 | |
| | 277 | Cooler { component_id, cooler_type, cooler_height, cooler_max_tdp_supported } |
| | 278 | |
| | 279 | Memory_Card { component_id, memory_card_num_slots, memory_card_interface } |
| | 280 | |
| | 281 | Optical_Drive { component_id, optical_drive_form_factor, optical_drive_type, optical_drive_interface, optical_drive_write_speed, optical_drive_read_speed } |
| | 282 | |
| | 283 | Sound_Card { component_id, sound_card_sample_rate, sound_card_bit_depth, sound_card_chipset, sound_card_interface, sound_card_channel } |
| | 284 | |
| | 285 | Cables { component_id, cables_length_cm, cables_type } |
| | 286 | |
| | 287 | Network_Adapter { component_id, network_adapter_wifi_version, network_adapter_interface, network_adapter_num_antennas } |
| | 288 | |
| | 289 | Network_Card { component_id, network_card_num_ports, network_card_speed, network_card_interface } |
| | 290 | |
| | 291 | Pc_Case_Storage_Form_Factor { component_id, pc_case_storage_form_factor , num_slots } |
| | 292 | |
| | 293 | Pc_Case_Ps_Form_Factor { component_id, pc_case_ps_form_factor } |
| | 294 | |
| | 295 | Pc_Case_Mobo_Form_Factor { component_id, pc_case_mobo_form_factor } |
| | 296 | |
| | 297 | Cooler_Cpu_Socket { component_id, cooler_cpu_socket } |
| | 298 | |
| | 299 | Build { build_id, user_id, build_name, build_created_at, build_description, build_total_price, build_is_approved } |
| | 300 | |
| | 301 | Build_Component { build_id, component_id, num_components } |
| | 302 | |
| | 303 | Rating_Build { build_id, user_id, rating_build_value } |
| | 304 | |
| | 305 | Favorite_Build { build_id, user_id } |
| | 306 | |
| | 307 | Review { review_id, build_id, user_id, review_content, review_created_at } |
| | 308 | |
| | 309 | Suggestion { suggestion_id, user_id, suggestion_admin_id, suggestion_link, suggestion_admin_comment, suggestion_description, suggestion_status, suggestion_component_type } |
| | 310 | |
| | 311 | For better contextualization we will add the Admins table which is just a specialization of Users, that has admin_id which references user_id in Users. |
| | 312 | |
| | 313 | Admins { admin_id } - BCNF |
| | 314 | |
| | 315 | |
| | 316 | |
| | 317 | |
| | 318 | |
| | 319 | |
| | 320 | |