| 276 | | {{{Dependency preservation:}}} |
| 277 | | [[BR]] |
| 278 | | To verify dependency preservation, we check whether the union of the projections of the functional dependencies onto each resulting relation is equivalent to the original set of functional dependencies: |
| 279 | | |
| 280 | | (⋃ projection of F onto Ri)+ = F+ |
| 281 | | |
| 282 | | In this decomposition, each functional dependency from the initial set (FD1–FD15) is fully contained within at least one of the resulting relations. |
| 283 | | |
| 284 | | For example: |
| 285 | | - user_id → user attributes is preserved in UserEntity |
| 286 | | - course_id → course attributes is preserved in Course |
| 287 | | - subscription_id → subscription attributes is preserved in UserSubscription |
| 288 | | |
| 289 | | Since no functional dependency is lost and all can be enforced locally within the resulting relations, the decomposition is dependency-preserving. |
| 290 | | {{{ |
| 291 | | The same argument applies to all resulting relations, since each relation is constructed around a determinant that forms its key. |
| 292 | | }}} |
| | 276 | {{{R2: SubscriptionPlan:}}} |
| | 277 | |
| | 278 | - !SubscriptionPlan(plan_id, plan_name, price, duration_months, plan_description, access_type) |
| | 279 | |
| | 280 | PK: plan_id |
| | 281 | |
| | 282 | - Derived from: |
| | 283 | |
| | 284 | FD4: plan_id → plan_name, price, duration_months, plan_description, access_type |
| | 285 | |
| | 286 | - Lossless Join Check: |
| | 287 | |
| | 288 | R ∩ !SubscriptionPlan = {plan_id} |
| | 289 | |
| | 290 | plan_id → !SubscriptionPlan |
| | 291 | |
| | 292 | ⇒ The decomposition is lossless |
| | 293 | |
| | 294 | - Dependency Preservation: |
| | 295 | |
| | 296 | FD4 is preserved |
| | 297 | |
| | 298 | ⇒ PRESERVED |
| | 299 | |
| | 300 | {{{R3: UserSubscription:}}} |
| | 301 | |
| | 302 | - !UserSubscription(subscription_id, user_id, plan_id, start_date, end_date, subscription_status) |
| | 303 | |
| | 304 | PK: subscription_id |
| | 305 | |
| | 306 | - Derived from: |
| | 307 | |
| | 308 | FD5: subscription_id → user_id, plan_id, start_date, end_date, subscription_status |
| | 309 | |
| | 310 | - Lossless Join Check: |
| | 311 | |
| | 312 | R ∩ !UserSubscription = {subscription_id} |
| | 313 | |
| | 314 | subscription_id → !UserSubscription |
| | 315 | |
| | 316 | ⇒ The decomposition is lossless |
| | 317 | |
| | 318 | - Dependency Preservation: |
| | 319 | |
| | 320 | FD5 is preserved |
| | 321 | |
| | 322 | ⇒ PRESERVED |
| | 323 | |
| | 324 | {{{R4: Payment:}}} |
| | 325 | |
| | 326 | - !Payment(payment_id, user_id, subscription_id, amount) |
| | 327 | |
| | 328 | PK: payment_id |
| | 329 | |
| | 330 | - Derived from: |
| | 331 | |
| | 332 | FD6: payment_id → user_id, subscription_id, amount |
| | 333 | |
| | 334 | - Lossless Join Check: |
| | 335 | |
| | 336 | R ∩ !Payment = {payment_id} |
| | 337 | |
| | 338 | payment_id → !Payment |
| | 339 | |
| | 340 | ⇒ The decomposition is lossless |
| | 341 | |
| | 342 | - Dependency Preservation: |
| | 343 | |
| | 344 | FD6 is preserved |
| | 345 | |
| | 346 | ⇒ PRESERVED |
| | 347 | |
| | 348 | {{{R5: SupportTicket:}}} |
| | 349 | |
| | 350 | - !SupportTicket(ticket_id, user_id, admin_id, subject, ticket_description, ticket_status, created_at) |
| | 351 | |
| | 352 | PK: ticket_id |
| | 353 | |
| | 354 | - Derived from: |
| | 355 | |
| | 356 | FD7: ticket_id → user_id, admin_id, subject, ticket_description, ticket_status, created_at |
| | 357 | |
| | 358 | - Lossless Join Check: |
| | 359 | |
| | 360 | R ∩ !SupportTicket = {ticket_id} |
| | 361 | |
| | 362 | ticket_id → !SupportTicket |
| | 363 | |
| | 364 | ⇒ The decomposition is lossless |
| | 365 | |
| | 366 | - Dependency Preservation: |
| | 367 | |
| | 368 | FD7 is preserved |
| | 369 | |
| | 370 | ⇒ PRESERVED |
| | 371 | |
| | 372 | {{{R6: Category:}}} |
| | 373 | |
| | 374 | - !Category(category_id, category_name, category_description) |
| | 375 | |
| | 376 | PK: category_id |
| | 377 | |
| | 378 | - Derived from: |
| | 379 | |
| | 380 | FD8: category_id → category_name, category_description |
| | 381 | |
| | 382 | - Lossless Join Check: |
| | 383 | |
| | 384 | R ∩ !Category = {category_id} |
| | 385 | |
| | 386 | category_id → !Category |
| | 387 | |
| | 388 | ⇒ The decomposition is lossless |
| | 389 | |
| | 390 | - Dependency Preservation: |
| | 391 | |
| | 392 | FD8 is preserved |
| | 393 | |
| | 394 | ⇒ PRESERVED |
| | 395 | |
| | 396 | {{{R7: Course:}}} |
| | 397 | |
| | 398 | - !Course(course_id, course_name, course_price, course_status, instructor_id) |
| | 399 | |
| | 400 | PK: course_id |
| | 401 | |
| | 402 | - Derived from: |
| | 403 | |
| | 404 | FD9: course_id → course_name, course_price, course_status, instructor_id |
| | 405 | |
| | 406 | - Lossless Join Check: |
| | 407 | |
| | 408 | R ∩ !Course = {course_id} |
| | 409 | |
| | 410 | course_id → !Course |
| | 411 | |
| | 412 | ⇒ The decomposition is lossless |
| | 413 | |
| | 414 | - Dependency Preservation: |
| | 415 | |
| | 416 | FD9 is preserved |
| | 417 | |
| | 418 | ⇒ PRESERVED |
| | 419 | |
| | 420 | {{{R8: Module:}}} |
| | 421 | |
| | 422 | - !Module(module_id, course_id, module_title, module_description) |
| | 423 | |
| | 424 | PK: module_id |
| | 425 | |
| | 426 | - Derived from: |
| | 427 | |
| | 428 | FD10: module_id → course_id, module_title, module_description |
| | 429 | |
| | 430 | - Lossless Join Check: |
| | 431 | |
| | 432 | R ∩ !Module = {module_id} |
| | 433 | |
| | 434 | module_id → !Module |
| | 435 | |
| | 436 | ⇒ The decomposition is lossless |
| | 437 | |
| | 438 | - Dependency Preservation: |
| | 439 | |
| | 440 | FD10 is preserved |
| | 441 | |
| | 442 | {{{R9: Lesson:}}} |
| | 443 | |
| | 444 | - !Lesson(lesson_id, module_id, lesson_title, material) |
| | 445 | |
| | 446 | PK: lesson_id |
| | 447 | |
| | 448 | - Derived from: |
| | 449 | |
| | 450 | FD11: lesson_id → module_id, lesson_title, material |
| | 451 | |
| | 452 | - Lossless Join Check: |
| | 453 | |
| | 454 | R ∩ !Lesson = {lesson_id} |
| | 455 | |
| | 456 | lesson_id → !Lesson |
| | 457 | |
| | 458 | ⇒ The decomposition is lossless |
| | 459 | |
| | 460 | - Dependency Preservation: |
| | 461 | |
| | 462 | FD11 is preserved |
| | 463 | |
| | 464 | {{{R10: Quiz:}}} |
| | 465 | |
| | 466 | - !Quiz(quiz_id, lesson_id, total_points, passing_score) |
| | 467 | |
| | 468 | PK: quiz_id |
| | 469 | |
| | 470 | - Derived from: |
| | 471 | |
| | 472 | FD12: quiz_id → lesson_id, total_points, passing_score |
| | 473 | |
| | 474 | - Lossless Join Check: |
| | 475 | |
| | 476 | R ∩ !Quiz = {quiz_id} |
| | 477 | |
| | 478 | quiz_id → !Quiz |
| | 479 | |
| | 480 | ⇒ The decomposition is lossless |
| | 481 | |
| | 482 | - Dependency Preservation: |
| | 483 | |
| | 484 | FD12 is preserved |
| | 485 | |
| | 486 | |
| | 487 | {{{R11: QuizAttempt:}}} |
| | 488 | |
| | 489 | - !QuizAttempt(attempt_id, user_id, quiz_id, score, attempt_date) |
| | 490 | |
| | 491 | PK: attempt_id |
| | 492 | |
| | 493 | - Derived from: |
| | 494 | |
| | 495 | FD13: attempt_id → user_id, quiz_id, score, attempt_date |
| | 496 | |
| | 497 | - Lossless Join Check: |
| | 498 | |
| | 499 | R ∩ !QuizAttempt = {attempt_id} |
| | 500 | |
| | 501 | attempt_id → !QuizAttempt |
| | 502 | |
| | 503 | ⇒ The decomposition is lossless |
| | 504 | |
| | 505 | - Dependency Preservation: |
| | 506 | |
| | 507 | FD13 is preserved |
| | 508 | |
| | 509 | {{{R12: Enrollment:}}} |
| | 510 | |
| | 511 | - !Enrollment(enrollment_id, user_id, course_id, enroll_date, completion_status, progress_percentage) |
| | 512 | |
| | 513 | PK: enrollment_id |
| | 514 | |
| | 515 | - Derived from: |
| | 516 | |
| | 517 | FD14: enrollment_id → user_id, course_id, enroll_date, completion_status, progress_percentage |
| | 518 | |
| | 519 | - Lossless Join Check: |
| | 520 | |
| | 521 | R ∩ !Enrollment = {enrollment_id} |
| | 522 | |
| | 523 | enrollment_id → !Enrollment |
| | 524 | |
| | 525 | ⇒ The decomposition is lossless |
| | 526 | |
| | 527 | - Dependency Preservation: |
| | 528 | |
| | 529 | FD14 is preserved |
| | 530 | |
| | 531 | {{{R13: Certificate:}}} |
| | 532 | |
| | 533 | - !Certificate(certificate_id, enrollment_id, issue_date, certificate_code, certificate_status) |
| | 534 | |
| | 535 | PK: certificate_id |
| | 536 | |
| | 537 | - Derived from: |
| | 538 | |
| | 539 | FD15: certificate_id → enrollment_id, issue_date, certificate_code, certificate_status |
| | 540 | |
| | 541 | - Lossless Join Check: |
| | 542 | |
| | 543 | R ∩ !Certificate = {certificate_id} |
| | 544 | |
| | 545 | certificate_id → !Certificate |
| | 546 | |
| | 547 | ⇒ The decomposition is lossless |
| | 548 | |
| | 549 | - Dependency Preservation: |
| | 550 | |
| | 551 | FD15 is preserved |
| | 552 | |
| | 553 | ⇒ PRESERVED |
| | 554 | |
| | 555 | {{{R14: CourseCategory:}}} |
| | 556 | - !CourseCategory(course_id, category_id) |
| | 557 | |
| | 558 | PK: (course_id, category_id) |
| | 559 | |
| | 560 | This relation represents a many-to-many relationship and contains no additional non-trivial functional dependencies. |
| | 561 | |
| | 562 | Final Result of 2NF Decomposition |
| | 563 | After removing all partial dependencies, the resulting schema consists of relations where: |
| | 564 | - Every non-key attribute depends on the whole primary key |
| | 565 | - no partial dependencies remain |
| | 566 | |
| | 567 | Therefore, the decomposition satisfies Second Normal Form (2NF). |