| | 434 | === R10 – REGISTRAR === |
| | 435 | |
| | 436 | {registrar_id} → {name, contact, location, working_hours} |
| | 437 | |
| | 438 | === Candidate Key Verification === |
| | 439 | |
| | 440 | registrar_id is the surrogate primary key. |
| | 441 | |
| | 442 | No partial dependencies exist. |
| | 443 | |
| | 444 | === Sample Data === |
| | 445 | |
| | 446 | || registrar_id || name || contact || location || working_hours || |
| | 447 | || 1 || Skopje Civil Registry || +38970123456 || Skopje || 08:00-16:00 || |
| | 448 | || 2 || Centar Registry || +38970222333 || Skopje || 09:00-17:00 || |
| | 449 | |
| | 450 | === Lossless Join Test === |
| | 451 | |
| | 452 | R9.1 ∩ R10 = {registrar_id, name, contact, location, working_hours} |
| | 453 | |
| | 454 | Since: |
| | 455 | |
| | 456 | registrar_id → R10 |
| | 457 | |
| | 458 | The decomposition is lossless. |
| | 459 | |
| | 460 | ---- |
| | 461 | |
| | 462 | === R11 – REGISTRAR_BOOKING === |
| | 463 | |
| | 464 | {booking_id} → {date, start_time, end_time, status, registrar_id, wedding_id} |
| | 465 | |
| | 466 | === Candidate Key Verification === |
| | 467 | |
| | 468 | booking_id is the surrogate primary key. |
| | 469 | |
| | 470 | No partial dependencies exist. |
| | 471 | |
| | 472 | === Sample Data === |
| | 473 | |
| | 474 | || booking_id || date || start_time || end_time || status || registrar_id || wedding_id || |
| | 475 | || 1 || 2026-06-20 || 10:00 || 10:30 || confirmed || 1 || 1 || |
| | 476 | || 2 || 2026-09-05 || 11:00 || 11:30 || confirmed || 2 || 2 || |
| | 477 | |
| | 478 | === Lossless Join Test === |
| | 479 | |
| | 480 | R10.1 ∩ R11 = {registrar_booking_id, date, start_time, end_time, status, registrar_id, wedding_id} |
| | 481 | |
| | 482 | Since: |
| | 483 | |
| | 484 | registrar_booking_id → R11 |
| | 485 | |
| | 486 | The decomposition is lossless. |
| | 487 | |
| | 488 | ---- |
| | 489 | |
| | 490 | === R12 – CHURCH === |
| | 491 | |
| | 492 | {church_id} → {name, location, contact, wedding_id} |
| | 493 | |
| | 494 | === Candidate Key Verification === |
| | 495 | |
| | 496 | church_id is the surrogate primary key. |
| | 497 | |
| | 498 | No partial dependencies exist. |
| | 499 | |
| | 500 | === Sample Data === |
| | 501 | |
| | 502 | || church_id || name || location || contact || wedding_id || |
| | 503 | || 1 || St. Clement Church || Skopje || contact@church.mk || 1 || |
| | 504 | || 2 || St. Panteleimon || Nerezi || info@church.mk || 2 || |
| | 505 | |
| | 506 | === Lossless Join Test === |
| | 507 | |
| | 508 | R11.1 ∩ R12 = {church_id, church_name, location, contact, wedding_id} |
| | 509 | |
| | 510 | Since: |
| | 511 | |
| | 512 | church_id → R12 |
| | 513 | |
| | 514 | The decomposition is lossless. |
| | 515 | |
| | 516 | ---- |
| | 517 | |
| | 518 | === R13 – PRIEST === |
| | 519 | |
| | 520 | {priest_id} → {name, contact, church_id} |
| | 521 | |
| | 522 | === Candidate Key Verification === |
| | 523 | |
| | 524 | priest_id is the surrogate primary key. |
| | 525 | |
| | 526 | No partial dependencies exist. |
| | 527 | |
| | 528 | === Sample Data === |
| | 529 | |
| | 530 | || priest_id || name || contact || church_id || |
| | 531 | || 1 || Father Nikola || +38970123456 || 1 || |
| | 532 | || 2 || Father Petar || +38970222333 || 2 || |
| | 533 | |
| | 534 | === Lossless Join Test === |
| | 535 | |
| | 536 | R12.1 ∩ R13 = {priest_id, priest_name, priest_contact, church_id} |
| | 537 | |
| | 538 | Since: |
| | 539 | |
| | 540 | priest_id → R13 |
| | 541 | |
| | 542 | The decomposition is lossless. |
| | 543 | |
| | 544 | ---- |
| | 545 | |
| | 546 | === R14 – EVENT === |
| | 547 | |
| | 548 | {event_id} → {event_type, date, start_time, end_time, status, wedding_id} |
| | 549 | |
| | 550 | === Candidate Key Verification === |
| | 551 | |
| | 552 | event_id is the surrogate primary key. |
| | 553 | |
| | 554 | No partial dependencies exist. |
| | 555 | |
| | 556 | === Sample Data === |
| | 557 | |
| | 558 | || event_id || event_type || date || start_time || end_time || status || wedding_id || |
| | 559 | || 1 || Ceremony || 2026-06-20 || 12:00 || 13:00 || scheduled || 1 || |
| | 560 | || 2 || Reception || 2026-06-20 || 16:00 || 23:00 || scheduled || 1 || |
| | 561 | |
| | 562 | === Lossless Join Test === |
| | 563 | |
| | 564 | R13.1 ∩ R14 = {event_id, event_type, date, start_time, end_time, status, wedding_id} |
| | 565 | |
| | 566 | Since: |
| | 567 | |
| | 568 | event_id → R14 |
| | 569 | |
| | 570 | The decomposition is lossless. |
| | 571 | |
| | 572 | ---- |
| | 573 | |
| | 574 | === R15 – GUEST === |
| | 575 | |
| | 576 | {guest_id} → {first_name, last_name, email, wedding_id} |
| | 577 | |
| | 578 | === Candidate Key Verification === |
| | 579 | |
| | 580 | guest_id is the surrogate primary key. |
| | 581 | |
| | 582 | No partial dependencies exist. |
| | 583 | |
| | 584 | === Sample Data === |
| | 585 | |
| | 586 | || guest_id || first_name || last_name || email || wedding_id || |
| | 587 | || 1 || Ana || Markovska || ana.m@gmail.com || 1 || |
| | 588 | || 2 || Daniel || Stojanov || daniel.s@gmail.com || 1 || |
| | 589 | |
| | 590 | === Lossless Join Test === |
| | 591 | |
| | 592 | R14.1 ∩ R15 = {guest_id, first_name, last_name, email, wedding_id} |
| | 593 | |
| | 594 | Since: |
| | 595 | |
| | 596 | guest_id → R15 |
| | 597 | |
| | 598 | The decomposition is lossless. |
| | 599 | |
| | 600 | ---- |
| | 601 | |
| | 602 | === R16 – EVENT_RSVP === |
| | 603 | |
| | 604 | {response_id} → {status, response_date, guest_id, event_id} |
| | 605 | |
| | 606 | === Candidate Key Verification === |
| | 607 | |
| | 608 | response_id is the surrogate primary key. |
| | 609 | |
| | 610 | No partial dependencies exist. |
| | 611 | |
| | 612 | === Sample Data === |
| | 613 | |
| | 614 | || response_id || status || response_date || guest_id || event_id || |
| | 615 | || 1 || accepted || 2026-05-15 || 1 || 1 || |
| | 616 | || 2 || accepted || 2026-05-15 || 2 || 2 || |
| | 617 | |
| | 618 | === Lossless Join Test === |
| | 619 | |
| | 620 | R15.1 ∩ R16 = {response_id, status, response_date, guest_id, event_id} |
| | 621 | |
| | 622 | Since: |
| | 623 | |
| | 624 | response_id → R16 |
| | 625 | |
| | 626 | The decomposition is lossless. |
| | 627 | |
| | 628 | ---- |
| | 629 | |
| | 630 | === R17 – ATTENDANCE === |
| | 631 | |
| | 632 | {attendance_id} → {status, table_number, role, guest_id, event_id} |
| | 633 | |
| | 634 | === Candidate Key Verification === |
| | 635 | |
| | 636 | attendance_id is the surrogate primary key. |
| | 637 | |
| | 638 | No partial dependencies exist. |
| | 639 | |
| | 640 | === Sample Data === |
| | 641 | |
| | 642 | || attendance_id || status || table_number || role || guest_id || event_id || |
| | 643 | || 1 || attending || 5 || Guest || 1 || 2 || |
| | 644 | || 2 || attending || 7 || Guest || 2 || 2 || |
| | 645 | |
| | 646 | === Lossless Join Test === |
| | 647 | |
| | 648 | R16.1 ∩ R17 = {attendance_id, status, table_number, role, guest_id, event_id} |
| | 649 | |
| | 650 | Since: |
| | 651 | |
| | 652 | attendance_id → R17 |
| | 653 | |
| | 654 | The decomposition is lossless. |
| | 655 | |
| | 656 | == Third Normal Form (3NF) == |
| | 657 | |
| | 658 | === Definition === |
| | 659 | |
| | 660 | A relation is in 3NF if: |
| | 661 | |
| | 662 | * It is already in 2NF |
| | 663 | * No transitive dependencies exist |
| | 664 | * Every non-key attribute depends only on the primary key |
| | 665 | |
| | 666 | === Transition from 2NF to 3NF === |
| | 667 | |
| | 668 | After decomposition into 2NF, each relation is examined for transitive dependencies. |
| | 669 | |
| | 670 | A transitive dependency exists when a non-key attribute depends on another non-key attribute. |
| | 671 | |
| | 672 | Example: |
| | 673 | |
| | 674 | venue_id → type_id → type_name |
| | 675 | |
| | 676 | Here: |
| | 677 | |
| | 678 | * type_name depends on type_id |
| | 679 | * type_id depends on venue_id |
| | 680 | |
| | 681 | Therefore type_name does not directly depend on the primary key venue_id. |
| | 682 | |
| | 683 | This violates 3NF. |
| | 684 | |
| | 685 | === Resolution === |
| | 686 | |
| | 687 | To eliminate the transitive dependency: |
| | 688 | |
| | 689 | * VENUE_TYPE(type_id, type_name) is extracted as a separate relation |
| | 690 | * VENUE stores type_id as a foreign key |
| | 691 | |
| | 692 | This preserves all functional dependencies while eliminating transitivity. |
| | 693 | |
| | 694 | === Verification of Remaining Relations === |
| | 695 | |
| | 696 | All remaining relations are examined and found to contain: |
| | 697 | |
| | 698 | * No partial dependencies |
| | 699 | * No transitive dependencies |
| | 700 | * Only direct dependencies on the primary key |
| | 701 | |
| | 702 | Therefore all final relations satisfy 3NF. |
| | 703 | |
| | 704 | == Boyce-Codd Normal Form (BCNF) == |
| | 705 | |
| | 706 | === Definition === |
| | 707 | |
| | 708 | A relation is in BCNF if for every non-trivial functional dependency: |
| | 709 | |
| | 710 | X → Y |
| | 711 | |
| | 712 | X is a superkey. |
| | 713 | |
| | 714 | === BCNF Verification === |
| | 715 | |
| | 716 | Each final relation satisfies BCNF because: |
| | 717 | |
| | 718 | * Every determinant is a candidate key or superkey |
| | 719 | * No dependency violates BCNF conditions |
| | 720 | |
| | 721 | == Final Schema Summary == |
| | 722 | |
| | 723 | || Relation || Primary Key || Foreign Keys || Normal Form || |
| | 724 | || USER || user_id || — || 3NF / BCNF || |
| | 725 | || WEDDING || wedding_id || user_id → USER || 3NF / BCNF || |
| | 726 | || VENUE_TYPE || type_id || — || 3NF / BCNF || |
| | 727 | || VENUE || venue_id || type_id → VENUE_TYPE || 3NF / BCNF || |
| | 728 | || VENUE_BOOKING || booking_id || venue_id → VENUE, wedding_id → WEDDING || 3NF / BCNF || |
| | 729 | || PHOTOGRAPHER || photographer_id || — || 3NF / BCNF || |
| | 730 | || PHOTOGRAPHER_BOOKING || booking_id || photographer_id → PHOTOGRAPHER, wedding_id → WEDDING || 3NF / BCNF || |
| | 731 | || BAND || band_id || — || 3NF / BCNF || |
| | 732 | || BAND_BOOKING || booking_id || band_id → BAND, wedding_id → WEDDING || 3NF / BCNF || |
| | 733 | || REGISTRAR || registrar_id || — || 3NF / BCNF || |
| | 734 | || REGISTRAR_BOOKING || booking_id || registrar_id → REGISTRAR, wedding_id → WEDDING || 3NF / BCNF || |
| | 735 | || CHURCH || church_id || wedding_id → WEDDING || 3NF / BCNF || |
| | 736 | || PRIEST || priest_id || church_id → CHURCH || 3NF / BCNF || |
| | 737 | || EVENT || event_id || wedding_id → WEDDING || 3NF / BCNF || |
| | 738 | || GUEST || guest_id || wedding_id → WEDDING || 3NF / BCNF || |
| | 739 | || EVENT_RSVP || response_id || guest_id → GUEST, event_id → EVENT || 3NF / BCNF || |
| | 740 | || ATTENDANCE || attendance_id || guest_id → GUEST, event_id → EVENT || 3NF / BCNF || |
| | 741 | |
| | 742 | == Final Conclusion == |
| | 743 | |
| | 744 | Through formal normalization analysis, verified functional dependencies, candidate key analysis, and lossless join decomposition tests, the Wedding Planner database schema has been fully normalized. |
| | 745 | |
| | 746 | The normalization process successfully: |
| | 747 | |
| | 748 | * Eliminates redundancy |
| | 749 | * Prevents insertion anomalies |
| | 750 | * Prevents deletion anomalies |
| | 751 | * Prevents update anomalies |
| | 752 | * Preserves all functional dependencies |
| | 753 | * Guarantees lossless joins |
| | 754 | * Ensures entity integrity through verified primary keys |
| | 755 | |
| | 756 | The final schema consists of 17 relations, all satisfying Third Normal Form (3NF) and Boyce-Codd Normal Form (BCNF). |