| 274 | | and is not in 2NF. |
| 275 | | |
| 276 | | ==== 1. PRODUCT(product_id, format, price, product_description, stock) |
| 277 | | |
| 278 | | |
| 279 | | {{{ |
| 280 | | R1 = R - {release_id, format, price, product_description, stock} |
| 281 | | |
| 282 | | R1 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 283 | | artist_id, artist_name, artist_description, artist_photo, release_id, title, record_label, genre, release_date, cover_photo, duration, |
| 284 | | album_id, song_id, song_name, song_duration, order_id, payment_method, purchase_date, points_earned, points_used, status, modification_id, |
| 285 | | admin_id, date_modified, type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, |
| 286 | | type, song_ordinal, product_id} |
| 287 | | }}} |
| 288 | | |
| 289 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{product_id}}}. |
| 290 | | |
| 291 | | * **Dependency preservation:** The dependency {{{product_id → release_id, format, price, product_description, stock}}} is preserved in the new ''PRODUCT'' relation. |
| | 274 | and is not in 2NF, requiring a 2NF decomposition. |
| | 275 | |
| | 276 | |
| | 277 | The order of decomposition is not arbitrary. Relations are extracted in an order that ensures that an intermediate determinant remains available until every dependency that requires it has been handled. |
| | 278 | |
| | 279 | In particular: |
| | 280 | |
| | 281 | * {{{release_id}}} must remain available until RELEASE_ARTISTS is extracted, because {{{(release_id, artist_id) → release_ordinal, type}}}. |
| | 282 | * {{{admin_id}}} must remain available until ADMIN is extracted, before it is later removed together with MODIFICATION. |
| | 283 | * {{{user_id}}} must remain available until USER, CONSUMER and WISHLIST are extracted, before it is later removed as part of ORDER. |
| | 284 | * {{{wishlist_id}}} must remain available until WISHLIST_PRODUCTS is extracted. |
| | 285 | * {{{release_id}}} is only removed from the residual relation when PRODUCT is decomposed at the end. |
| | 286 | |
| | 287 | This order therefore preserves the determinants required by later decompositions and avoids removing an attribute before all dependencies involving it have been handled. |
| | 288 | |
| | 289 | |
| | 290 | ==== 1. RELEASE(release_id, title, record_label, genre, release_date, cover_photo, duration) |
| | 291 | |
| | 292 | The attributes of RELEASE are determined by {{{release_id}}}: |
| | 293 | |
| | 294 | {{{ |
| | 295 | release_id → title, record_label, genre, release_date, cover_photo, duration |
| | 296 | }}} |
| | 297 | |
| | 298 | Although {{{release_id}}} is not itself part of K, it is determined by the proper subset {{{product_id}}} of K: |
| | 299 | |
| | 300 | {{{ |
| | 301 | product_id → release_id |
| | 302 | }}} |
| | 303 | |
| | 304 | Therefore, by transitivity: |
| | 305 | |
| | 306 | {{{ |
| | 307 | product_id → title, record_label, genre, release_date, cover_photo, duration |
| | 308 | }}} |
| | 309 | |
| | 310 | so these attributes are partially dependent on the candidate key. |
| | 311 | |
| | 312 | {{{ |
| | 313 | R1 = R - {title, record_label, genre, release_date, cover_photo, duration} |
| | 314 | |
| | 315 | R1 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_id, admin_type, discount_percentage, |
| | 316 | points_collected, artist_id, artist_name, artist_description, artist_photo, release_id, album_id, song_id, song_name, song_duration, |
| | 317 | product_id, format, price, product_description, stock, order_id, payment_method, purchase_date, points_earned, points_used, status, |
| | 318 | modification_id, date_modified, type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, |
| | 319 | song_ordinal} |
| | 320 | }}} |
| | 321 | |
| | 322 | * **Lossless join:** The intersection between RELEASE and R1 is {{{release_id}}}. Since {{{release_id → title, record_label, genre, release_date, cover_photo, duration}}}, {{{release_id}}} functionally determines all attributes of RELEASE. Therefore, joining RELEASE and R1 on {{{release_id}}} reconstructs the original information. |
| | 323 | |
| | 324 | * **Dependency preservation:** FD07 is represented entirely inside RELEASE. Therefore {{{release_id → title, record_label, genre, release_date, cover_photo, duration}}} can still be enforced directly on this relation without joining it to another relation. |
| 300 | | R2 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 301 | | artist_id, release_id, title, record_label, genre, release_date, cover_photo, duration, album_id, song_id, song_name, song_duration, |
| 302 | | product_id, order_id, payment_method, purchase_date, points_earned, points_used, status, modification_id, admin_id, date_modified, |
| 303 | | type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| 304 | | }}} |
| 305 | | |
| 306 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{artist_id}}}. |
| 307 | | |
| 308 | | * **Dependency preservation:** The dependency {{{artist_id → artist_name, artist_description, artist_photo}}} is preserved in the new ''ARTIST'' relation. |
| 309 | | |
| 310 | | |
| 311 | | ==== 3. RELEASE(release_id, title, record_label, genre, release_date, cover_photo, duration) |
| 312 | | |
| 313 | | {{{ |
| 314 | | R3 = R2 - {title, record_label, genre, release_date, cover_photo, duration} |
| 315 | | |
| 316 | | R3 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 317 | | artist_id, release_id, album_id, song_id, song_name, song_duration, product_id, order_id, payment_method, purchase_date, |
| 318 | | points_earned, points_used, status, modification_id, admin_id, date_modified, type_of_modification, discount, wishlist_id, |
| 319 | | quantity, price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| 320 | | }}} |
| 321 | | |
| 322 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{release_id}}}. |
| 323 | | |
| 324 | | * **Dependency preservation:** The dependency {{{release_id → title, record_label, genre, release_date, cover_photo}}} is preserved in the new ''RELEASE'' relation. |
| 325 | | |
| 326 | | ==== 4. SONG(song_id, song_name, song_duration) |
| 327 | | |
| 328 | | {{{ |
| 329 | | R4 = R3 - {song_name, song_duration} |
| 330 | | |
| 331 | | R4 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 332 | | artist_id, release_id, album_id, song_id, product_id, order_id, payment_method, purchase_date, points_earned, points_used, status, |
| 333 | | modification_id, admin_id, date_modified, type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, |
| | 340 | R2 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_id, admin_type, discount_percentage, |
| | 341 | points_collected, artist_id, release_id, album_id, song_id, song_name, song_duration, product_id, format, price, product_description, stock, |
| | 342 | order_id, payment_method, purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, |
| | 343 | wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| | 344 | }}} |
| | 345 | |
| | 346 | * **Lossless join:** ARTIST and R2 intersect on {{{artist_id}}}. Since {{{artist_id}}} is the key of ARTIST and determines all its other attributes, the original relation can be reconstructed by joining on {{{artist_id}}} without creating spurious tuples. |
| | 347 | |
| | 348 | * **Dependency preservation:** FD06 is fully contained in ARTIST, so {{{artist_id → artist_name, artist_description, artist_photo}}} remains directly enforceable. |
| | 349 | |
| | 350 | |
| | 351 | ==== 3. SONG(song_id, song_name, song_duration) |
| | 352 | |
| | 353 | {{{ |
| | 354 | song_id → song_name, song_duration |
| | 355 | }}} |
| | 356 | |
| | 357 | Since {{{song_id}}} is a proper subset of K, this is a partial dependency. |
| | 358 | |
| | 359 | {{{ |
| | 360 | R3 = R2 - {song_name, song_duration} |
| | 361 | |
| | 362 | R3 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_id, admin_type, discount_percentage, |
| | 363 | points_collected, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 364 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id, quantity, |
| | 365 | price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| | 366 | }}} |
| | 367 | |
| | 368 | * **Lossless join:** SONG and R3 intersect on {{{song_id}}}. Since {{{song_id → song_name, song_duration}}}, the common attribute determines the complete SONG relation. The decomposition is therefore lossless. |
| | 369 | |
| | 370 | * **Dependency preservation:** FD08 is preserved entirely in SONG and can be checked without performing a join. |
| | 371 | |
| | 372 | |
| | 373 | ==== 4. ADMIN(admin_id, admin_type, discount_percentage) |
| | 374 | |
| | 375 | ADMIN is extracted before MODIFICATION because {{{admin_id}}} is needed here and will later be removed from the residual relation when FD11 is decomposed. |
| | 376 | |
| | 377 | {{{ |
| | 378 | admin_id → admin_type, discount_percentage |
| | 379 | }}} |
| | 380 | |
| | 381 | Furthermore: |
| | 382 | |
| | 383 | {{{ |
| | 384 | modification_id → admin_id |
| | 385 | }}} |
| | 386 | |
| | 387 | and {{{modification_id}}} is a proper subset of K. Therefore the admin attributes are ultimately determined by a proper subset of K. |
| | 388 | |
| | 389 | {{{ |
| | 390 | R4 = R3 - {admin_type, discount_percentage} |
| | 391 | |
| | 392 | R4 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_id, points_collected, artist_id, release_id, |
| | 393 | album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, purchase_date, points_earned, points_used, |
| | 394 | status, modification_id, date_modified, type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, |
| | 395 | type, song_ordinal} |
| | 396 | }}} |
| | 397 | |
| | 398 | * **Lossless join:** ADMIN and R4 intersect on {{{admin_id}}}. Since {{{admin_id → admin_type, discount_percentage}}}, the common attribute determines the whole ADMIN relation, making the decomposition lossless. |
| | 399 | |
| | 400 | * **Dependency preservation:** FD04 is fully contained in ADMIN and therefore remains directly enforceable. |
| | 401 | |
| | 402 | |
| | 403 | ==== 5. CONSUMER(user_id, points_collected) |
| | 404 | |
| | 405 | {{{ |
| | 406 | user_id → points_collected |
| | 407 | }}} |
| | 408 | |
| | 409 | Since: |
| | 410 | |
| | 411 | {{{ |
| | 412 | order_id → user_id |
| | 413 | }}} |
| | 414 | |
| | 415 | and {{{order_id}}} is a proper subset of K, {{{points_collected}}} is indirectly dependent on only part of K. |
| | 416 | |
| | 417 | {{{ |
| | 418 | R5 = R4 - {points_collected} |
| | 419 | |
| | 420 | R5 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_id, artist_id, release_id, album_id, song_id, |
| | 421 | product_id, format, price, product_description, stock, order_id, payment_method, purchase_date, points_earned, points_used, status, |
| | 422 | modification_id, date_modified, type_of_modification, discount, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, |
| | 423 | song_ordinal} |
| | 424 | }}} |
| | 425 | |
| | 426 | * **Lossless join:** CONSUMER and R5 intersect on {{{user_id}}}. Since {{{user_id → points_collected}}}, the shared attribute determines all of CONSUMER. |
| | 427 | |
| | 428 | * **Dependency preservation:** FD05 is preserved directly in CONSUMER. |
| | 429 | |
| | 430 | |
| | 431 | ==== 6. USER(user_id, email, username, password, date_created, shipping_address, telephone_number) |
| | 432 | |
| | 433 | USER is extracted before ORDER because ORDER will later remove {{{user_id}}} from the residual relation. |
| | 434 | |
| | 435 | {{{ |
| | 436 | user_id → email, username, password, date_created, shipping_address, telephone_number |
| | 437 | email → user_id |
| | 438 | username → user_id |
| | 439 | }}} |
| | 440 | |
| | 441 | Because {{{order_id → user_id}}} and {{{order_id}}} is a proper subset of K, the USER attributes are also ultimately determined by a proper subset of K. |
| | 442 | |
| | 443 | {{{ |
| | 444 | R6 = R5 - {email, username, password, date_created, shipping_address, telephone_number} |
| | 445 | |
| | 446 | R6 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 447 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id, quantity, |
| | 448 | price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| | 449 | }}} |
| | 450 | |
| | 451 | * **Lossless join:** USER and R6 intersect on {{{user_id}}}. Since {{{user_id}}} determines every other attribute of USER, the decomposition is lossless. |
| | 452 | |
| | 453 | * **Dependency preservation:** FD01, FD02 and FD03 are all contained in USER. Therefore both the primary identifier {{{user_id}}} and the alternate candidate keys {{{email}}} and {{{username}}} retain their functional dependencies. |
| | 454 | |
| | 455 | |
| | 456 | ==== 7. ORDER_PRODUCTS(order_id, product_id, price_at_purchase, quantity) |
| | 457 | |
| | 458 | {{{ |
| | 459 | (order_id, product_id) → price_at_purchase, quantity |
| | 460 | }}} |
| | 461 | |
| | 462 | The determinant {{{(order_id, product_id)}}} is a proper subset of K, so the dependency is partial. |
| | 463 | |
| | 464 | {{{ |
| | 465 | R7 = R6 - {price_at_purchase, quantity} |
| | 466 | |
| | 467 | R7 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 468 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id, added_at, |
| 337 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{song_id}}}. |
| 338 | | |
| 339 | | * **Dependency preservation:** The dependency {{{song_id → song_name, song_duration}}} is preserved in the new ''SONG'' relation. |
| 340 | | |
| 341 | | ==== 5. MODIFICATION(modification_id, admin_id, date_modified, type_of_modification, discount) |
| 342 | | |
| 343 | | {{{ |
| 344 | | R5 = R4 - {admin_id, date_modified, type_of_modification, discount} |
| 345 | | |
| 346 | | R5 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 347 | | artist_id, release_id, album_id, song_id, product_id, order_id, payment_method, purchase_date, points_earned, points_used, status, |
| 348 | | modification_id, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| 349 | | }}} |
| 350 | | |
| 351 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{modification_id}}}. |
| 352 | | |
| 353 | | * **Dependency preservation:** The dependency {{{modification_id → admin_id, date_modified, type_of_modification, discount}}} is preserved in the new ''MODIFICATION'' relation. |
| 354 | | |
| 355 | | ==== 6. ORDER(order_id, user_id, payment_method, purchase_date, points_earned, points_used, status) |
| 356 | | |
| 357 | | {{{ |
| 358 | | R6 = R5 - {payment_method, purchase_date, points_earned, points_used, status} |
| 359 | | |
| 360 | | R6 = {user_id, email, username, password, date_created, shipping_address, telephone_number, admin_type, discount_percentage, points_collected, |
| 361 | | artist_id, release_id, album_id, song_id, product_id, order_id, modification_id, wishlist_id, quantity, price_at_purchase, added_at, |
| | 472 | * **Lossless join:** ORDER_PRODUCTS and R7 intersect on {{{order_id, product_id}}}. This pair determines {{{price_at_purchase}}} and {{{quantity}}}, so the common attributes determine the complete ORDER_PRODUCTS relation. The decomposition is therefore lossless. |
| | 473 | |
| | 474 | * **Dependency preservation:** FD14 remains entirely inside ORDER_PRODUCTS. |
| | 475 | |
| | 476 | |
| | 477 | ==== 8. WISHLIST_PRODUCTS(wishlist_id, product_id, added_at) |
| | 478 | |
| | 479 | This relation must be created before WISHLIST removes {{{wishlist_id}}} from the residual relation. |
| | 480 | |
| | 481 | {{{ |
| | 482 | (wishlist_id, product_id) → added_at |
| | 483 | }}} |
| | 484 | |
| | 485 | Because {{{order_id → user_id → wishlist_id}}}, and both {{{order_id}}} and {{{product_id}}} belong to a proper subset of K, the determinant can ultimately be obtained from part of the candidate key. |
| | 486 | |
| | 487 | {{{ |
| | 488 | R8 = R7 - {added_at} |
| | 489 | |
| | 490 | R8 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 491 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id, |
| 365 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{order_id}}}. |
| 366 | | |
| 367 | | * **Dependency preservation:** The dependency {{{order_id → user_id, payment_method, purchase_date, points_earned, points_used, status}}} is preserved in the new ''ORDER'' relation. |
| 368 | | |
| 369 | | ==== 7. USER(user_id, email, username, password, date_created, shipping_address, telephone_number) |
| 370 | | |
| 371 | | {{{ |
| 372 | | R7 = R6 - {email, username, password, date_created, shipping_address, telephone_number} |
| 373 | | |
| 374 | | R7 = {user_id, admin_type, discount_percentage, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, |
| 375 | | modification_id, wishlist_id, quantity, price_at_purchase, added_at, release_ordinal, type, song_ordinal} |
| 376 | | }}} |
| 377 | | |
| 378 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{user_id}}}. |
| 379 | | |
| 380 | | * **Dependency preservation:** The dependency {{{user_id → email, username, password, date_created, shipping_address, telephone_number}}} is preserved in the new ''USER'' relation. |
| 381 | | |
| 382 | | ==== 8. ORDER_PRODUCTS(order_id, product_id, price_at_purchase, quantity) |
| 383 | | |
| 384 | | {{{ |
| 385 | | R8 = R7 - {price_at_purchase, quantity} |
| 386 | | |
| 387 | | R8 = {user_id, admin_type, discount_percentage, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, |
| 388 | | modification_id, wishlist_id, added_at, release_ordinal, type, song_ordinal} |
| 389 | | }}} |
| 390 | | |
| 391 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{order_id, product_id}}}. |
| 392 | | |
| 393 | | * **Dependency preservation:** The dependency {{{(order_id, product_id) → price_at_purchase, quantity}}} is preserved in the new ''ORDER_PRODUCTS'' relation. |
| 394 | | |
| 395 | | ==== 9. WISHLIST_PRODUCTS(wishlist_id, product_id, added_at) |
| 396 | | |
| 397 | | {{{ |
| 398 | | R9 = R8 - {added_at} |
| 399 | | |
| 400 | | R9 = {user_id, admin_type, discount_percentage, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, |
| 401 | | modification_id, wishlist_id, release_ordinal, type, song_ordinal} |
| 402 | | }}} |
| 403 | | |
| 404 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{wishlist_id, product_id}}}. |
| 405 | | |
| 406 | | * **Dependency preservation:** The dependency {{{(wishlist_id, product_id) → added_at}}} is preserved in the new ''WISHLIST_PRODUCTS'' relation. |
| 407 | | |
| 408 | | ==== 10. RELEASE_ARTISTS(release_id, artist_id, release_ordinal, type) |
| 409 | | |
| 410 | | {{{ |
| 411 | | R10 = R9 - {release_ordinal, type} |
| 412 | | |
| 413 | | R10 = {user_id, admin_type, discount_percentage, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, |
| 414 | | modification_id, wishlist_id, song_ordinal} |
| 415 | | }}} |
| 416 | | |
| 417 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{release_id, artist_id}}}. |
| 418 | | |
| 419 | | * **Dependency preservation:** The dependency {{{(release_id, artist_id) → release_ordinal, type}}} is preserved in the new ''RELEASE_ARTISTS'' relation. |
| 420 | | |
| 421 | | ==== 11. SONG_ARTISTS(song_id, artist_id, song_ordinal) |
| 422 | | |
| 423 | | {{{ |
| 424 | | R11 = R10 - {song_ordinal} |
| 425 | | |
| 426 | | R11 = {user_id, admin_type, discount_percentage, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, |
| 427 | | modification_id, wishlist_id} |
| 428 | | }}} |
| 429 | | |
| 430 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{song_id, artist_id}}}. |
| 431 | | |
| 432 | | * **Dependency preservation:** The dependency {{{(song_id, artist_id) → song_ordinal}}} is preserved in the new ''SONG_ARTISTS'' relation. |
| 433 | | |
| 434 | | ==== 12. ADMIN(user_id, admin_type, discount_percentage) |
| 435 | | |
| 436 | | {{{ |
| 437 | | R12 = R11 - {admin_type, discount_percentage} |
| 438 | | |
| 439 | | R12 = {user_id, points_collected, artist_id, release_id, album_id, song_id, product_id, order_id, modification_id, wishlist_id} |
| 440 | | }}} |
| 441 | | |
| 442 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{user_id}}}. |
| 443 | | |
| 444 | | * **Dependency preservation:** The dependency {{{user_id → admin_type, discount_percentage}}} is preserved in the new ''ADMIN'' relation. |
| 445 | | |
| 446 | | ==== 13. CONSUMER(user_id, points_collected) |
| 447 | | |
| 448 | | {{{ |
| 449 | | R13 = R12 - {points_collected} |
| 450 | | |
| 451 | | R13 = {user_id, artist_id, release_id, album_id, song_id, product_id, order_id, modification_id, wishlist_id} |
| 452 | | }}} |
| 453 | | |
| 454 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{user_id}}}. |
| 455 | | |
| 456 | | * **Dependency preservation:** The dependency {{{user_id → points_collected}}} is preserved in the new ''CONSUMER'' relation. |
| 457 | | |
| 458 | | ==== 14. WISHLIST(user_id, wishlist_id) |
| 459 | | |
| 460 | | {{{ |
| 461 | | R14 = R13 - {wishlist_id} |
| 462 | | |
| 463 | | R14 = {user_id, artist_id, release_id, album_id, song_id, product_id, order_id, modification_id} |
| 464 | | }}} |
| 465 | | |
| 466 | | * **Lossless join:** The original relation can be reconstructed through a join using {{{user_id}}}. |
| 467 | | |
| 468 | | * **Dependency preservation:** The dependencies {{{user_id → wishlist_id}}} and {{{wishlist_id → user_id}}} are preserved in the new ''WISHLIST'' relation. |
| 469 | | |
| 470 | | ==== 15. Removing Remaining Partial Dependencies |
| 471 | | |
| 472 | | Two non-prime attributes remain: |
| 473 | | |
| 474 | | 1. {{{order_id → user_id}}} |
| 475 | | 2. {{{product_id → release_id}}} |
| 476 | | |
| 477 | | Since {{{order_id}}} and {{{product_id}}} are proper subsets of the candidate key, these are still partial dependencies. However, these dependencies are already represented in ''ORDER'' and ''PRODUCT''. |
| 478 | | |
| 479 | | {{{ |
| 480 | | R15 = R14 - {user_id, release_id} |
| 481 | | |
| 482 | | R15 = {artist_id, release_id, album_id, song_id, product_id, |
| 483 | | order_id, modification_id} |
| 484 | | }}} |
| 485 | | |
| 486 | | * **Lossless join:** The removed {{{user_id}}} can be recovered through the existing ''ORDER'' relation using {{{order_id}}} and the removed {{{release_id}}} can be recovered through the existing ''PRODUCT'' relation using {{{product_id}}}. |
| 487 | | |
| 488 | | * **Dependency preservation:** The dependency {{{order_id → user_id}}} remains preserved in the existing ''ORDER'' relation and the dependency {{{product_id → release_id}}} remains preserved in the existing ''PRODUCT'' relation. |
| 489 | | |
| 490 | | }}} |
| | 495 | * **Lossless join:** WISHLIST_PRODUCTS and R8 intersect on {{{wishlist_id, product_id}}}. These attributes determine {{{added_at}}}, so the common attributes determine the full WISHLIST_PRODUCTS relation. |
| | 496 | |
| | 497 | * **Dependency preservation:** FD15 is preserved entirely inside WISHLIST_PRODUCTS. |
| | 498 | |
| | 499 | |
| | 500 | ==== 9. RELEASE_ARTISTS(release_id, artist_id, release_ordinal, type) |
| | 501 | |
| | 502 | This relation is extracted before PRODUCT because PRODUCT will later remove {{{release_id}}} from the residual relation. |
| | 503 | |
| | 504 | {{{ |
| | 505 | (release_id, artist_id) → release_ordinal, type |
| | 506 | }}} |
| | 507 | |
| | 508 | Since {{{product_id → release_id}}}, the pair {{{(product_id, artist_id)}}}, which is a proper subset of K, can determine these attributes. |
| | 509 | |
| | 510 | {{{ |
| | 511 | R9 = R8 - {release_ordinal, type} |
| | 512 | |
| | 513 | R9 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 514 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id, song_ordinal} |
| | 515 | }}} |
| | 516 | |
| | 517 | * **Lossless join:** RELEASE_ARTISTS and R9 intersect on {{{release_id, artist_id}}}. This composite determinant determines {{{release_ordinal}}} and {{{type}}}, so the decomposition is lossless. |
| | 518 | |
| | 519 | * **Dependency preservation:** FD16 is fully contained in RELEASE_ARTISTS. |
| | 520 | |
| | 521 | |
| | 522 | ==== 10. SONG_ARTISTS(song_id, artist_id, song_ordinal) |
| | 523 | |
| | 524 | {{{ |
| | 525 | (song_id, artist_id) → song_ordinal |
| | 526 | }}} |
| | 527 | |
| | 528 | The determinant {{{(song_id, artist_id)}}} is a proper subset of K. |
| | 529 | |
| | 530 | {{{ |
| | 531 | R10 = R9 - {song_ordinal} |
| | 532 | |
| | 533 | R10 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 534 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount, wishlist_id} |
| | 535 | }}} |
| | 536 | |
| | 537 | * **Lossless join:** SONG_ARTISTS and R10 intersect on {{{song_id, artist_id}}}. Since the pair determines {{{song_ordinal}}}, it determines the entire SONG_ARTISTS relation. |
| | 538 | |
| | 539 | * **Dependency preservation:** FD17 remains directly represented inside SONG_ARTISTS. |
| | 540 | |
| | 541 | |
| | 542 | ==== 11. WISHLIST(user_id, wishlist_id) |
| | 543 | |
| | 544 | The following two dependencies hold: |
| | 545 | |
| | 546 | {{{ |
| | 547 | wishlist_id → user_id |
| | 548 | user_id → wishlist_id |
| | 549 | }}} |
| | 550 | |
| | 551 | WISHLIST is decomposed only after WISHLIST_PRODUCTS because {{{wishlist_id}}} will now be removed from the residual relation. |
| | 552 | |
| | 553 | {{{ |
| | 554 | R11 = R10 - {wishlist_id} |
| | 555 | |
| | 556 | R11 = {user_id, admin_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 557 | purchase_date, points_earned, points_used, status, modification_id, date_modified, type_of_modification, discount} |
| | 558 | }}} |
| | 559 | |
| | 560 | * **Lossless join:** WISHLIST and R11 intersect on {{{user_id}}}. Since {{{user_id → wishlist_id}}}, {{{user_id}}} determines the complete WISHLIST relation. Therefore the split is lossless. |
| | 561 | |
| | 562 | * **Dependency preservation:** Both FD12 and FD13 remain inside WISHLIST, since both {{{user_id}}} and {{{wishlist_id}}} are contained in the same relation. |
| | 563 | |
| | 564 | |
| | 565 | ==== 12. MODIFICATION(modification_id, admin_id, date_modified, type_of_modification, discount) |
| | 566 | |
| | 567 | ADMIN has already been extracted, so {{{admin_id}}} can now safely be removed from the residual relation. |
| | 568 | |
| | 569 | {{{ |
| | 570 | modification_id → admin_id, date_modified, type_of_modification, discount |
| | 571 | }}} |
| | 572 | |
| | 573 | Since {{{modification_id}}} is a proper subset of K, this is a partial dependency. |
| | 574 | |
| | 575 | {{{ |
| | 576 | R12 = R11 - {admin_id, date_modified, type_of_modification, discount} |
| | 577 | |
| | 578 | R12 = {user_id, artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, payment_method, |
| | 579 | purchase_date, points_earned, points_used, status, modification_id} |
| | 580 | }}} |
| | 581 | |
| | 582 | * **Lossless join:** MODIFICATION and R12 intersect on {{{modification_id}}}. Since {{{modification_id}}} determines all remaining MODIFICATION attributes, the original information can be reconstructed without spurious tuples. |
| | 583 | |
| | 584 | * **Dependency preservation:** FD11 is preserved entirely inside MODIFICATION. FD04 has already been preserved separately inside ADMIN. |
| | 585 | |
| | 586 | |
| | 587 | ==== 13. ORDER(order_id, user_id, payment_method, purchase_date, points_earned, points_used, status) |
| | 588 | |
| | 589 | USER, CONSUMER and WISHLIST have already been extracted, so {{{user_id}}} can now be removed from the residual relation. |
| | 590 | |
| | 591 | {{{ |
| | 592 | order_id → user_id, payment_method, purchase_date, points_earned, points_used, status |
| | 593 | }}} |
| | 594 | |
| | 595 | Since {{{order_id}}} is a proper subset of K, this is a partial dependency. |
| | 596 | |
| | 597 | {{{ |
| | 598 | R13 = R12 - {user_id, payment_method, purchase_date, points_earned, points_used, status} |
| | 599 | |
| | 600 | R13 = {artist_id, release_id, album_id, song_id, product_id, format, price, product_description, stock, order_id, modification_id} |
| | 601 | }}} |
| | 602 | |
| | 603 | * **Lossless join:** ORDER and R13 intersect on {{{order_id}}}. Since {{{order_id}}} determines all attributes of ORDER, the decomposition is lossless. |
| | 604 | |
| | 605 | * **Dependency preservation:** FD10 is fully preserved inside ORDER. The dependencies involving {{{user_id}}} have already been preserved in USER, CONSUMER and WISHLIST before {{{user_id}}} was removed from the residual relation. |
| | 606 | |
| | 607 | |
| | 608 | ==== 14. PRODUCT(product_id, release_id, format, price, product_description, stock) |
| | 609 | |
| | 610 | PRODUCT is decomposed last among the identifier-bearing relations because {{{release_id}}} was needed earlier for RELEASE and RELEASE_ARTISTS. |
| | 611 | |
| | 612 | {{{ |
| | 613 | product_id → release_id, format, price, product_description, stock |
| | 614 | }}} |
| | 615 | |
| | 616 | Since {{{product_id}}} is a proper subset of K, this is a partial dependency. |
| | 617 | |
| | 618 | {{{ |
| | 619 | R14 = R13 - {release_id, format, price, product_description, stock} |
| | 620 | |
| | 621 | R14 = {artist_id, album_id, song_id, product_id, order_id, modification_id} |
| | 622 | }}} |
| | 623 | |
| | 624 | * **Lossless join:** PRODUCT and R14 intersect on {{{product_id}}}. Since {{{product_id}}} determines {{{release_id, format, price, product_description, stock}}}, the shared attribute determines the entire PRODUCT relation. Therefore the decomposition is lossless. |
| | 625 | |
| | 626 | * **Dependency preservation:** FD09 is fully contained inside PRODUCT. The dependency involving {{{release_id}}} has already been preserved in RELEASE and RELEASE_ARTISTS before {{{release_id}}} was removed from the residual relation. |
| | 627 | |
| | 628 | |
| | 629 | ==== Residual Relation |
| | 630 | |
| | 631 | After all partial dependencies have been removed, the residual relation is: |
| | 632 | |
| | 633 | {{{ |
| | 634 | R14 = {artist_id, album_id, song_id, product_id, order_id, modification_id} |
| | 635 | }}} |
| | 636 | |
| | 637 | This residual relation consists only of attributes belonging to the candidate key: |
| | 638 | |
| | 639 | {{{ |
| | 640 | K = {order_id, product_id, artist_id, song_id, modification_id, album_id} |
| | 641 | }}} |
| | 642 | |
| | 643 | Therefore there are no non-prime attributes left in R14 that can be partially dependent on a proper subset of the candidate key. |
| | 644 | |
| | 645 | Consequently, the decomposition has removed all partial dependencies from the universal relation and the resulting relations satisfy 2NF. |
| 619 | | 1. PRODUCT(**product_id**, release_id, format, price, product_description, stock) → **satisfies BCNF** |
| 620 | | 2. ARTIST(**artist_id**, artist_name, artist_description, artist_photo) → satisfies BCNF |
| 621 | | 3. RELEASE(**release_id**, title, record_label, genre, release_date, cover_photo, duration) → **satisfies BCNF** |
| 622 | | 4. SONG(**song_id**, song_name, song_duration) → satisfies BCNF |
| 623 | | 5. MODIFICATION(**modification_id**, admin_id, date_modified, type_of_modification, discount) → **satisfies BCNF** |
| 624 | | 6. ORDER(**order_id**, user_id, payment_method, purchase_date, points_earned, points_used, status) → **satisfies BCNF** |
| 625 | | 7. USER(**user_id**, email, username, password, date_created, shipping_address, telephone_number) → **satisfies BCNF** |
| 626 | | 8. ORDER_PRODUCTS(**order_id**, **product_id**, price_at_purchase, quantity) → **satisfies BCNF** |
| 627 | | 9. WISHLIST_PRODUCTS(**wishlist_id**, **product_id**, added_at) → **satisfies BCNF** |
| 628 | | 10. RELEASE_ARTISTS(**release_id**, **artist_id**, release_ordinal, release_artist_type) → **satisfies BCNF** |
| 629 | | 11. SONG_ARTISTS(**song_id**, **artist_id**, song_ordinal) → **satisfies BCNF** |
| 630 | | 12. ADMIN(**user_id**, admin_type, discount_percentage) → **satisfies BCNF** |
| 631 | | 13. CONSUMER(**user_id**, points_collected) → **satisfies BCNF** |
| 632 | | 14. WISHLIST(**wishlist_id**, user_id) → **satisfies BCNF** |
| 633 | | 15. R15 = {**artist_id**, **album_id**, **song_id**, **product_id**, **order_id**, **modification_id**} → **satisfies BCNF** |
| | 790 | 1. RELEASE(**release_id**, title, record_label, genre, release_date, cover_photo, duration) → **satisfies BCNF** |
| | 791 | |
| | 792 | The only non-trivial functional dependency is {{{release_id → title, record_label, genre, release_date, cover_photo, duration}}}. Since {{{release_id}}} is the primary key and therefore a superkey, RELEASE satisfies BCNF. |
| | 793 | |
| | 794 | 2. ARTIST(**artist_id**, artist_name, artist_description, artist_photo) → **satisfies BCNF** |
| | 795 | |
| | 796 | The only non-trivial functional dependency is {{{artist_id → artist_name, artist_description, artist_photo}}}. Since {{{artist_id}}} is the primary key and therefore a superkey, ARTIST satisfies BCNF. |
| | 797 | |
| | 798 | 3. SONG(**song_id**, song_name, song_duration) → **satisfies BCNF** |
| | 799 | |
| | 800 | The only non-trivial functional dependency is {{{song_id → song_name, song_duration}}}. Since {{{song_id}}} is the primary key and therefore a superkey, SONG satisfies BCNF. |
| | 801 | |
| | 802 | 4. ADMIN(**admin_id**, admin_type, discount_percentage) → **satisfies BCNF** |
| | 803 | |
| | 804 | The only non-trivial functional dependency is {{{admin_id → admin_type, discount_percentage}}}. Since {{{admin_id}}} is the primary key and therefore a superkey, ADMIN satisfies BCNF. |
| | 805 | |
| | 806 | 5. CONSUMER(**user_id**, points_collected) → **satisfies BCNF** |
| | 807 | |
| | 808 | The only non-trivial functional dependency is {{{user_id → points_collected}}}. Since {{{user_id}}} is the primary key and therefore a superkey, CONSUMER satisfies BCNF. |
| | 809 | |
| | 810 | 6. USER(**user_id**, email, username, password, date_created, shipping_address, telephone_number) → **satisfies BCNF** |
| | 811 | |
| | 812 | The relevant functional dependencies are: |
| | 813 | |
| | 814 | {{{ |
| | 815 | user_id → email, username, password, date_created, shipping_address, telephone_number |
| | 816 | email → user_id |
| | 817 | username → user_id |
| | 818 | }}} |
| | 819 | |
| | 820 | {{{user_id}}}, {{{email}}}, and {{{username}}} are all candidate keys of USER. Therefore, every determinant in a non-trivial functional dependency is a superkey, so USER satisfies BCNF. |
| | 821 | |
| | 822 | 7. ORDER_PRODUCTS(**order_id**, **product_id**, price_at_purchase, quantity) → **satisfies BCNF** |
| | 823 | |
| | 824 | The non-trivial functional dependency is {{{(order_id, product_id) → price_at_purchase, quantity}}}. The determinant {{{(order_id, product_id)}}} is the complete composite primary key and therefore a superkey. ORDER_PRODUCTS satisfies BCNF. |
| | 825 | |
| | 826 | 8. WISHLIST_PRODUCTS(**wishlist_id**, **product_id**, added_at) → **satisfies BCNF** |
| | 827 | |
| | 828 | The non-trivial functional dependency is {{{(wishlist_id, product_id) → added_at}}}. The determinant {{{(wishlist_id, product_id)}}} is the complete composite primary key and therefore a superkey. WISHLIST_PRODUCTS satisfies BCNF. |
| | 829 | |
| | 830 | 9. RELEASE_ARTISTS(**release_id**, **artist_id**, release_ordinal, release_artist_type) → **satisfies BCNF** |
| | 831 | |
| | 832 | The non-trivial functional dependency is {{{(release_id, artist_id) → release_ordinal, release_artist_type}}}. The determinant {{{(release_id, artist_id)}}} is the complete composite primary key and therefore a superkey. RELEASE_ARTISTS satisfies BCNF. |
| | 833 | |
| | 834 | 10. SONG_ARTISTS(**song_id**, **artist_id**, song_ordinal) → **satisfies BCNF** |
| | 835 | |
| | 836 | The non-trivial functional dependency is {{{(song_id, artist_id) → song_ordinal}}}. The determinant {{{(song_id, artist_id)}}} is the complete composite primary key and therefore a superkey. SONG_ARTISTS satisfies BCNF. |
| | 837 | |
| | 838 | 11. WISHLIST(**wishlist_id**, user_id) → **satisfies BCNF** |
| | 839 | |
| | 840 | The relevant functional dependencies are: |
| | 841 | |
| | 842 | {{{ |
| | 843 | wishlist_id → user_id |
| | 844 | user_id → wishlist_id |
| | 845 | }}} |
| | 846 | |
| | 847 | Both {{{wishlist_id}}} and {{{user_id}}} are candidate keys of WISHLIST. Therefore, both determinants are superkeys and WISHLIST satisfies BCNF. |
| | 848 | |
| | 849 | 12. MODIFICATION(**modification_id**, admin_id, date_modified, type_of_modification, discount) → **satisfies BCNF** |
| | 850 | |
| | 851 | The only non-trivial functional dependency within MODIFICATION is {{{modification_id → admin_id, date_modified, type_of_modification, discount}}}. Since {{{modification_id}}} is the primary key and therefore a superkey, MODIFICATION satisfies BCNF. |
| | 852 | |
| | 853 | 13. ORDER(**order_id**, user_id, payment_method, purchase_date, points_earned, points_used, status) → **satisfies BCNF** |
| | 854 | |
| | 855 | The only non-trivial functional dependency within ORDER is {{{order_id → user_id, payment_method, purchase_date, points_earned, points_used, status}}}. Since {{{order_id}}} is the primary key and therefore a superkey, ORDER satisfies BCNF. |
| | 856 | |
| | 857 | 14. PRODUCT(**product_id**, release_id, format, price, product_description, stock) → **satisfies BCNF** |
| | 858 | |
| | 859 | The only non-trivial functional dependency within PRODUCT is {{{product_id → release_id, format, price, product_description, stock}}}. Since {{{product_id}}} is the primary key and therefore a superkey, PRODUCT satisfies BCNF. |
| | 860 | |
| | 861 | 15. R14 = {**artist_id**, **album_id**, **song_id**, **product_id**, **order_id**, **modification_id**} → **satisfies BCNF** |
| | 862 | |
| | 863 | R14 contains only the attributes of the candidate key remaining after the 2NF decomposition. Under the current set of functional dependencies, there are no non-trivial functional dependencies within R14 whose determinant is not a superkey. Therefore, R14 satisfies BCNF. |
| | 864 | |
| | 865 | Since every non-trivial functional dependency in every relation has a superkey as its determinant, all relations obtained after the 3NF analysis already satisfy BCNF. |
| | 866 | |
| | 867 | Therefore, no further decomposition is required. |