Changes between Version 13 and Version 14 of Normalization


Ignore:
Timestamp:
07/02/26 13:00:19 (4 days ago)
Author:
233062
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v13 v14  
    1515- **FD1:** `user_id -> email, username, password`
    1616- **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`)
    1818- **FD4:** `training_id -> training_user_id, training_date, training_type, training_duration, training_calories`
    1919- **FD5:** `user_id -> weight_current, weight_height, weight_goal_weight, weight_goal_calories`
     
    4848`user_id`, `training_user_id`, `discipline_user_id`, `custom_tracking_id`
    4949
    50 Овие атрибути **не можат** да бидат дел од кандидат клуч бидејќи не детерминираат ништо надвор од себе.
     50Овие атрибути се детерминанти во одредени FD (на пример `user_id` детерминира `email`, `training_gender` итн.), но не мора да бидат дел од минималниот кандидат клуч бидејќи **веќе се изведливи** од атрибутите кои се само на левата страна (на пример `user_id` се изведува од `asset_id` преку FD7, `training_user_id` се изведува од `training_id` преку FD4 итн.).
    5151
    5252**Атрибути кои се само на лева страна** (мора да бидат во секој кандидат клуч):
     
    103103- income_id -> user_id, income_date, income_amount
    104104
     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
    105107== **Декомпозиција по 2НФ** ==
    106108
     
    165167R4 = R3 - {task_name, task_is_finished}
    166168
     169**Напомена:** Иако FD10 ги одредува и `discipline_user_id` и `custom_tracking_id`, тие НЕ се отстрануваат од R4 бидејќи се истовремено детерминанти (FD8, FD9) и ќе бидат формално обработени во 3НФ чекорите. Се отстрануваат само „листовите" атрибути `task_name` и `task_is_finished` кои не детерминираат ништо друго.
     170
    167171R4 = {user_id, email, username, password, training_gender, training_age, training_weight,
    168172training_id, asset_id, daily_intake_id,
     
    179183
    1801845. **DailyCompletion(daily_completion_id, user_id, daily_completion_date, daily_completion_procent)**
     185
     186**Напомена:** `DailyCompletion.user_id` е FK директно кон `USERS`, не кон `DISCIPLINE_USERS`. Ова е дизајнерска одлука: дневното завршување (`procent`) е агрегатна мера за целиот корисник, не е врзана само за корисници со дисциплински профил. Затоа нема потреба да минува низ `DISCIPLINE_USERS`.
    181187
    182188R5 = R4 - {daily_completion_date, daily_completion_procent}
     
    316322
    317323
    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` на корисникот, декомпозираме:
     3246. Во **R11** важи FD8: `discipline_user_id -> user_id`. И `discipline_user_id` и `user_id` се не-клучни атрибути во R11, па постои транзитивна зависност. Декомпозираме:
    319325
    320326**DisciplineUsers(user_id)** — `user_id` е примарен и надворешен клуч кон `Users`. `discipline_user_id` во `Tasks` е FK кон `DisciplineUsers.user_id`.
     
    325331
    326332
    327 7. **InvestorUsers(user_id)** е структурна (role) табела — `user_id` е примарен и надворешен клуч кон `Users`. `Assets.user_id` е FK кон `InvestorUsers.user_id`, со што се обезбедува дека само корисници со инвеститорски профил можат да поседуваат активи. Не произлегува од FD нарушување туку од дизајнерскиот избор за разграничување на профилите.
     3337. **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
     335Lossless join: Релацијата може да се реконструира преку join со `(task_id, daily_completion_id)`.
     336
     337
     3388. **InvestorUsers(user_id)** е структурна (role) табела — `user_id` е примарен и надворешен клуч кон `Users`. `Assets.user_id` е FK кон `InvestorUsers.user_id`, со што се обезбедува дека само корисници со инвеститорски профил можат да поседуваат активи. Не произлегува од FD нарушување туку од дизајнерскиот избор за разграничување на профилите.
    328339
    329340Lossless join: Релацијата може да се реконструира преку join со `user_id`.
     
    34835915. R11 = {user_id, training_id, asset_id, daily_intake_id,
    349360    discipline_user_id, custom_tracking_id, task_id, daily_completion_id, income_id}
     361    (R11 не е физичка табела — сите нејзини атрибути се примарни или надворешни клучеви кои веќе живеат во нивните соодветни извлечени релации. R11 е артефакт на процесот на декомпозиција и се „раствора" во финалниот модел.)
    350362
    351363== **Проверка дали добиените релации се во 3НФ** ==
     
    374386- (Условот CHECK (точно еден FK е NOT NULL) е ограничување на домен, не FD)
    375387
     388**DAILY_COMPLETION(daily_completion_id, user_id, daily_completion_date, daily_completion_procent)**
     389- PK: `daily_completion_id`
     390- Не-клучен `user_id` не детерминира ништо во оваа релација → во 3НФ ✓
     391
    376392**INCOMES(income_id, user_id, income_date, income_amount)**
    377393- PK: `income_id`
     
    396412
    3974135. 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-от. Двете детерминанти се суперклучеви, па БКНФ важи.)
    398415
    3994166. InvestorUsers(**user_id**) -> **задоволува БКНФ**
     
    41543214. Incomes(**income_id**, user_id, income_date, income_amount) -> **задоволува БКНФ**
    416433
    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**} -> **задоволува БКНФ**
     43415. R11 = {**training_id, asset_id, user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, income_id**} -> **задоволува БКНФ** (R11 е артефакт на декомпозицијата — не е физичка табела; сите атрибути се клучеви кои живеат во нивните соодветни релации)
    418435
    419436**Заклучок:** **Целиот модел е во БКНФ.**
     
    448465
    449466DAILY_INTAKES(daily_intake_id, user_id, date, calories)
    450 PK: daily_intake_id   FK: user_id -> WEIGHT_USERS(user_id)
     467PK: daily_intake_id   CK: {daily_intake_id}, {user_id, date}   FK: user_id -> WEIGHT_USERS(user_id)
     468UNIQUE: (user_id, date) — бизнис правило: еден корисник има најмногу еден внес по датум
    451469
    452470INVESTOR_USERS(user_id)