Changes between Version 13 and Version 14 of Normalization
- Timestamp:
- 07/02/26 13:00:19 (4 days ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Normalization
v13 v14 15 15 - **FD1:** `user_id -> email, username, password` 16 16 - **FD2:** `user_id -> training_gender, training_age, training_weight` 17 - **FD3:** `training_user_id -> user_id` 17 - **FD3:** `training_user_id -> user_id` (конкретно кон `TRAINING_USERS.user_id`, кој преку shared PK pattern е ист со `USERS.user_id`) 18 18 - **FD4:** `training_id -> training_user_id, training_date, training_type, training_duration, training_calories` 19 19 - **FD5:** `user_id -> weight_current, weight_height, weight_goal_weight, weight_goal_calories` … … 48 48 `user_id`, `training_user_id`, `discipline_user_id`, `custom_tracking_id` 49 49 50 Овие атрибути **не можат** да бидат дел од кандидат клуч бидејќи не детерминираат ништо надвор од себе.50 Овие атрибути се детерминанти во одредени FD (на пример `user_id` детерминира `email`, `training_gender` итн.), но не мора да бидат дел од минималниот кандидат клуч бидејќи **веќе се изведливи** од атрибутите кои се само на левата страна (на пример `user_id` се изведува од `asset_id` преку FD7, `training_user_id` се изведува од `training_id` преку FD4 итн.). 51 51 52 52 **Атрибути кои се само на лева страна** (мора да бидат во секој кандидат клуч): … … 103 103 - income_id -> user_id, income_date, income_amount 104 104 105 **Напомена:** Атрибутите зависни од `user_id` (`email`, `username`, `password`, `training_gender`, `training_age`, `training_weight`, `weight_current`, `weight_height`, `weight_goal_weight`, `weight_goal_calories`, `finance_spending_budget`, `finance_saving_budget`, `finance_investing_budget`, `finance_donation_budget`, `finance_credit`) не се групираат тука и остануваат во остатокот R6. Причината е што нивниот директен детерминант е `user_id`, кој е **не-примарен** атрибут (не е дел од K). Затоа тие претставуваат транзитивни зависности (проблем за 3НФ), а не парцијални зависности (проблем за 2НФ), и се обработуваат во чекорот за 3НФ. 106 105 107 == **Декомпозиција по 2НФ** == 106 108 … … 165 167 R4 = R3 - {task_name, task_is_finished} 166 168 169 **Напомена:** Иако FD10 ги одредува и `discipline_user_id` и `custom_tracking_id`, тие НЕ се отстрануваат од R4 бидејќи се истовремено детерминанти (FD8, FD9) и ќе бидат формално обработени во 3НФ чекорите. Се отстрануваат само „листовите" атрибути `task_name` и `task_is_finished` кои не детерминираат ништо друго. 170 167 171 R4 = {user_id, email, username, password, training_gender, training_age, training_weight, 168 172 training_id, asset_id, daily_intake_id, … … 179 183 180 184 5. **DailyCompletion(daily_completion_id, user_id, daily_completion_date, daily_completion_procent)** 185 186 **Напомена:** `DailyCompletion.user_id` е FK директно кон `USERS`, не кон `DISCIPLINE_USERS`. Ова е дизајнерска одлука: дневното завршување (`procent`) е агрегатна мера за целиот корисник, не е врзана само за корисници со дисциплински профил. Затоа нема потреба да минува низ `DISCIPLINE_USERS`. 181 187 182 188 R5 = R4 - {daily_completion_date, daily_completion_procent} … … 316 322 317 323 318 6. Во ** Tasks(task_id, discipline_user_id, custom_tracking_id, task_name, task_is_finished)** важи FD8: `discipline_user_id -> user_id`. Бидејќи `discipline_user_id` во `Tasks` секогаш е еднакво на `user_id` на корисникот, декомпозираме:324 6. Во **R11** важи FD8: `discipline_user_id -> user_id`. И `discipline_user_id` и `user_id` се не-клучни атрибути во R11, па постои транзитивна зависност. Декомпозираме: 319 325 320 326 **DisciplineUsers(user_id)** — `user_id` е примарен и надворешен клуч кон `Users`. `discipline_user_id` во `Tasks` е FK кон `DisciplineUsers.user_id`. … … 325 331 326 332 327 7. **InvestorUsers(user_id)** е структурна (role) табела — `user_id` е примарен и надворешен клуч кон `Users`. `Assets.user_id` е FK кон `InvestorUsers.user_id`, со што се обезбедува дека само корисници со инвеститорски профил можат да поседуваат активи. Не произлегува од FD нарушување туку од дизајнерскиот избор за разграничување на профилите. 333 7. **TaskDailyCompletion(task_id, daily_completion_id)** е структурна спојна (junction) табела — и `task_id` и `daily_completion_id` се клучни атрибути (дел од K), па FD12 не е транзитивна зависност и не претставува 3НФ нарушување. Релацијата произлегува од дизајнерската одлука за M:N врска помеѓу `TASKS` и `DAILY_COMPLETION`: една задача може да биде дел од повеќе дневни завршувања и обратно. `task_id` е FK кон `Tasks`, `daily_completion_id` е FK кон `DailyCompletion`. 334 335 Lossless join: Релацијата може да се реконструира преку join со `(task_id, daily_completion_id)`. 336 337 338 8. **InvestorUsers(user_id)** е структурна (role) табела — `user_id` е примарен и надворешен клуч кон `Users`. `Assets.user_id` е FK кон `InvestorUsers.user_id`, со што се обезбедува дека само корисници со инвеститорски профил можат да поседуваат активи. Не произлегува од FD нарушување туку од дизајнерскиот избор за разграничување на профилите. 328 339 329 340 Lossless join: Релацијата може да се реконструира преку join со `user_id`. … … 348 359 15. R11 = {user_id, training_id, asset_id, daily_intake_id, 349 360 discipline_user_id, custom_tracking_id, task_id, daily_completion_id, income_id} 361 (R11 не е физичка табела — сите нејзини атрибути се примарни или надворешни клучеви кои веќе живеат во нивните соодветни извлечени релации. R11 е артефакт на процесот на декомпозиција и се „раствора" во финалниот модел.) 350 362 351 363 == **Проверка дали добиените релации се во 3НФ** == … … 374 386 - (Условот CHECK (точно еден FK е NOT NULL) е ограничување на домен, не FD) 375 387 388 **DAILY_COMPLETION(daily_completion_id, user_id, daily_completion_date, daily_completion_procent)** 389 - PK: `daily_completion_id` 390 - Не-клучен `user_id` не детерминира ништо во оваа релација → во 3НФ ✓ 391 376 392 **INCOMES(income_id, user_id, income_date, income_amount)** 377 393 - PK: `income_id` … … 396 412 397 413 5. DailyIntakes(**daily_intake_id**, user_id, daily_intake_date, daily_intake_calories) -> **задоволува БКНФ** 414 (Покрај `daily_intake_id`, и `{user_id, daily_intake_date}` е кандидат клуч заради `UNIQUE (user_id, date)` constraint-от. Двете детерминанти се суперклучеви, па БКНФ важи.) 398 415 399 416 6. InvestorUsers(**user_id**) -> **задоволува БКНФ** … … 415 432 14. Incomes(**income_id**, user_id, income_date, income_amount) -> **задоволува БКНФ** 416 433 417 15. R11 = {**training_id, asset_id, user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, income_id**} -> **задоволува БКНФ** 434 15. R11 = {**training_id, asset_id, user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, income_id**} -> **задоволува БКНФ** (R11 е артефакт на декомпозицијата — не е физичка табела; сите атрибути се клучеви кои живеат во нивните соодветни релации) 418 435 419 436 **Заклучок:** **Целиот модел е во БКНФ.** … … 448 465 449 466 DAILY_INTAKES(daily_intake_id, user_id, date, calories) 450 PK: daily_intake_id FK: user_id -> WEIGHT_USERS(user_id) 467 PK: daily_intake_id CK: {daily_intake_id}, {user_id, date} FK: user_id -> WEIGHT_USERS(user_id) 468 UNIQUE: (user_id, date) — бизнис правило: еден корисник има најмногу еден внес по датум 451 469 452 470 INVESTOR_USERS(user_id)
