Changes between Version 6 and Version 7 of Normalization


Ignore:
Timestamp:
08/29/26 01:17:39 (2 weeks ago)
Author:
231020
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v6 v7  
    1010Universal_Relation_TradingMK(
    1111  user_id, username, password, email, role,
    12   auth_provider,
     12  auth_provider_id, auth_provider,
    1313  portfolio_id, balance,
    1414  holding_id, holding_quantity, avg_price,
    1515  stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated,
    1616  history_id, history_price, history_timestamp,
    17   trade_id, trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol,
    18   transaction_id, txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin,
     17  trade_id, trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id,
     18  transaction_id, txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, trade_request_id,
    1919  watchlist_id, price_above, price_below,
    20   oauth_token, oauth_email, oauth_provider, oauth_expires_at, oauth_created_at
     20  oauth_token, oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, oauth_auth_provider_id
    2121)
    2222}}}
    2323
    2424'''Напомени за именување:'''
    25  * trade_stock_symbol е преименуван (наспроти stock_symbol) за да избегне конфликт на имиња во универзалната релација
    26  * auth_provider е атрибут кој претставува вредност од user_auth_providers - повеќевредносен по природа
     25 * trade_stock_id е преименуван за јасно да се разликува од stock_id во останатите делови на универзалната релација
     26 * auth_provider_id е идентификатор на AuthProvider ентитетот
     27 * oauth_auth_provider_id е преименуван за да се избегне конфликт со auth_provider_id во универзалната релација
    2728 * Нема дупликати на имиња на атрибути во универзалната релација
    2829
     
    4142 * '''FD8:'''  holding_id → holding_quantity, avg_price, portfolio_id, stock_id
    4243 * '''FD9:'''  history_id → history_price, history_timestamp, stock_id
    43  * '''FD10:''' trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol, portfolio_id
    44  * '''FD11:''' transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id
     44 * '''FD10:''' trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id, portfolio_id
     45 * '''FD11:''' transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id, trade_request_id
    4546 * '''FD12:''' watchlist_id → price_above, price_below, user_id, stock_id
    46  * '''FD13:''' oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id
     47 * '''FD13:''' oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id, oauth_auth_provider_id
     48 * '''FD14:''' auth_provider_id → auth_provider
    4749'''}'''
    4850
     
    5961|| email || ✓ (FD3) || ✓ (FD1) || и лево и десно ||
    6062|| role || ✗ || ✓ (FD1) || само десно ||
    61 || auth_provider || ✗ || ✗ || '''не се јавува во ниедна FD''' ||
     63|| auth_provider_id || ✓ (FD14) || ✓ (FD13) || и лево и десно ||
     64|| auth_provider || ✗ || ✓ (FD14) || само десно ||
    6265|| portfolio_id || ✓ (FD4) || ✓ (FD5, FD8, FD10) || и лево и десно ||
    6366|| balance || ✗ || ✓ (FD4) || само десно ||
     
    8285|| price_per_unit || ✗ || ✓ (FD10) || само десно ||
    8386|| trade_timestamp || ✗ || ✓ (FD10) || само десно ||
    84 || trade_stock_symbol || ✗ || ✓ (FD10) || само десно ||
     87|| trade_stock_id || ✗ || ✓ (FD10) || само десно ||
    8588|| transaction_id || ✓ (FD11) || ✗ || '''само лево''' ||
    8689|| txn_type || ✗ || ✓ (FD11) || само десно ||
     
    8992|| txn_timestamp || ✗ || ✓ (FD11) || само десно ||
    9093|| txn_origin || ✗ || ✓ (FD11) || само десно ||
     94|| trade_request_id || ✗ || ✓ (FD11) || само десно ||
    9195|| watchlist_id || ✓ (FD12) || ✗ || '''само лево''' ||
    9296|| price_above || ✗ || ✓ (FD12) || само десно ||
     
    97101|| oauth_expires_at || ✗ || ✓ (FD13) || само десно ||
    98102|| oauth_created_at || ✗ || ✓ (FD13) || само десно ||
     103|| oauth_auth_provider_id || ✗ || ✓ (FD13) || само десно ||
    99104
    100105==== Атрибути кои се појавуваат САМО на лева страна ====
     
    108113 * '''watchlist_id''' - мора да биде дел од секој кандидат клуч
    109114 * '''oauth_token''' - мора да биде дел од секој кандидат клуч
    110  * '''auth_provider''' - мора да биде дел од секој кандидат клуч (не учествува во ниедна FD; изводливо само преку себе)
    111115
    112116==== Пресметка на затворач ====
     
    115119
    116120{{{
    117 {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token, auth_provider}:
     121{holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}:
    118122
    119123- Од FD8  (holding_id →):      holding_quantity, avg_price, portfolio_id, stock_id
    120124- Од FD9  (history_id →):      history_price, history_timestamp, stock_id
    121125- Од FD10 (trade_id →):        trade_type, trade_status, trade_quantity, price_per_unit,
    122                                 trade_timestamp, trade_stock_symbol, portfolio_id
    123 - Од FD11 (transaction_id →):  txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin,
    124                                 user_id, stock_id
     126                                trade_timestamp, trade_stock_id, portfolio_id
     127- Од FD11 (transaction_id →): txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin,
     128                                user_id, stock_id, trade_request_id
    125129- Од FD12 (watchlist_id →):    price_above, price_below, user_id, stock_id
    126 - Од FD13 (oauth_token →):     oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id
     130- Од FD13 (oauth_token →):     oauth_email, oauth_provider, oauth_expires_at,
     131                                oauth_created_at, user_id, oauth_auth_provider_id
    127132- Од FD4  (portfolio_id →):    balance, user_id
    128133- Од FD5  (user_id →):         portfolio_id
     
    133138- Од FD2  (username →):        user_id
    134139- Од FD3  (email →):           user_id
    135 }}}
    136 
    137 {{{
    138 {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token, auth_provider}
     140- Од FD14 (auth_provider_id →): auth_provider
     141}}}
     142
     143{{{
     144{holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}
    139145  = Universal_Relation_TradingMK ✓  (сите атрибути се изводливи)
    140146}}}
     
    146152|| без holding_id || holding_quantity, avg_price || ✗ НЕ ||
    147153|| без history_id || history_price, history_timestamp || ✗ НЕ ||
    148 || без trade_id || trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol || ✗ НЕ ||
    149 || без transaction_id || txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin || ✗ НЕ ||
     154|| без trade_id || trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id || ✗ НЕ ||
     155|| без transaction_id || txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, trade_request_id || ✗ НЕ ||
    150156|| без watchlist_id || price_above, price_below || ✗ НЕ ||
    151 || без oauth_token || oauth_email, oauth_expires_at, oauth_created_at || ✗ НЕ ||
    152 || без auth_provider || auth_provider не е изводливо || ✗ НЕ ||
     157|| без oauth_token || oauth_email, oauth_expires_at, oauth_created_at, oauth_auth_provider_id || ✗ НЕ ||
    153158
    154159Секој атрибут е неопходен - множеството е минимално.
     
    159164
    160165{{{
    161 PK = {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token, auth_provider}
    162 }}}
    163 
    164 '''Образложение:''' Примарниот клуч е голем бидејќи универзалната релација содржи повеќе независни ентитети (корисници, портфолија, акции, трговски барања, трансакции, watchlist записи, OAuth токени, auth провајдери) кои не се директно поврзани преку функционални зависности. Секој независен ентитет бара барем еден идентификатор во клучот. Клучот е минимален - отстранувањето на кој било атрибут го прави невозможно изведувањето на дел од атрибутите.
     166PK = {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}
     167}}}
     168
     169'''Образложение:''' Примарниот клуч е голем бидејќи универзалната релација содржи повеќе независни ентитети (корисници, портфолија, акции, трговски барања, трансакции, watchlist записи, OAuth токени и auth провајдери) кои не се директно поврзани преку функционални зависности. Секој независен ентитет бара барем еден идентификатор во клучот. Клучот е минимален - отстранувањето на кој било атрибут го прави невозможно изведувањето на дел од атрибутите.
    165170
    166171==== Нормална форма пред декомпозиција ====
    167172
    168 Universal_Relation_TradingMK е во '''1NF''' (сите атрибути се атомарни, со исклучок на auth_provider кој е мулти-вредносен). Релацијата '''НЕ е во 2NF''' поради следните парцијални зависности - секој идентификатор ги определува само своите атрибути, независно од останатиот примарен клуч:
     173Universal_Relation_TradingMK е во '''1NF''' бидејќи сите атрибути се атомарни. AuthProvider е моделиран како посебен ентитет преку auth_provider_id, па auth_provider повеќе не е мулти-вредносен атрибут во универзалната релација.
     174
     175Релацијата '''НЕ е во 2NF''' поради следните парцијални зависности - секој идентификатор ги определува само своите атрибути, независно од останатиот примарен клуч:
    169176
    170177 * FD8:  holding_id → holding_quantity, avg_price, portfolio_id, stock_id
    171178 * FD9:  history_id → history_price, history_timestamp, stock_id
    172179 * FD10: trade_id → trade_type, trade_status, ..., portfolio_id
    173  * FD11: transaction_id → txn_type, ..., user_id, stock_id
     180 * FD11: transaction_id → txn_type, ..., user_id, stock_id, trade_request_id
    174181 * FD12: watchlist_id → price_above, price_below, user_id, stock_id
    175  * FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id
     182 * FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id, oauth_auth_provider_id
     183 * FD14: auth_provider_id → auth_provider
    176184
    177185----
    178186
    179 == 1NF Декомпозиција ==
     187== 2NF Декомпозиција ==
     188
     189=== Дефиниција ===
     190
     191Релацијата е во 2NF ако е во 1NF и секој не-клучен атрибут целосно функционално зависи од целиот примарен клуч - нема парцијални зависности.
    180192
    181193=== Анализа ===
     
    183195'''Анализирана релација:''' Universal_Relation_TradingMK
    184196
    185 '''Функционални зависности:''' FD1 - FD13 (сите)
    186 
    187 '''Кандидат клуч / Примарен клуч:''' {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token, auth_provider}
    188 
    189 '''Нормална форма:''' Релацијата е делумно во 1NF - атрибутот '''auth_provider''' претставува повеќевредносен (multi-valued) атрибут. Еден корисник може да има повеќе auth провајдери (интерен, Google), па оваа вредност не може да биде атомарна во унификованата релација.
    190 
    191 '''Зависност која го предизвикува проблемот:''' auth_provider е неделива повторувачка вредност поврзана со user_id - нема функционална зависност од единечен детерминант, туку претставува множество вредности.
    192 
    193 === Декомпозиција - Извлекување на auth_provider ===
    194 {{{
    195 User_Auth_Providers(user_id, auth_provider)
    196    PK: {user_id, auth_provider}
    197    FK: user_id → Users
    198 
    199 Universal_Relation_Base = Universal_Relation_TradingMK - {auth_provider}
    200    PK: {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}
    201 }}}
    202 
    203 '''Функционални зависности во User_Auth_Providers:''' нема FD освен дефиницијата на PK.
    204 
    205 '''Функционални зависности во Universal_Relation_Base:''' FD1 – FD13 (auth_provider отстранет).
    206 
    207 '''Кандидат клучеви во Universal_Relation_Base:''' {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}
    208 
    209 '''Проверка за lossless join:''' Декомпозицијата е lossless бидејќи заедничкиот атрибут user_id е клуч во Users и FK во User_Auth_Providers — секој auth_provider запис може недвосмислено да се поврзе со корисник. ✓
    210 
    211 '''Проверка за dependency preservation:''' Нема FD која ги поврзува само auth_provider атрибутите — релацијата е дефинирана преку бизнис логика (1:N врска). Сите 13 FD остануваат во Universal_Relation_Base. ✓
    212 
    213 '''Заклучок:''' Universal_Relation_Base е во 1NF. Продолжуваме со 2NF декомпозиција.
    214 
    215 ----
    216 == 2NF Декомпозиција ==
    217 
    218 === Дефиниција ===
    219 
    220 Релацијата е во 2NF ако е во 1NF и секој не-клучен атрибут целосно функционално зависи од целиот примарен клуч - нема парцијални зависности.
    221 
    222 === Анализа ===
    223 
    224 '''Анализирана релација:''' Universal_Relation_Base
    225 
    226197'''Примарен клуч:''' {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token}
    227198
     
    229200
    230201||= FD =||= Детерминант =||= Дел од PK? =||= Парцијална зависност? =||
    231 || FD8:  holding_id → holding_quantity, avg_price, portfolio_id, stock_id || holding_id || ДА || '''ДА''' ||
    232 || FD9:  history_id → history_price, history_timestamp, stock_id || history_id || ДА || '''ДА''' ||
    233 || FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol, portfolio_id || trade_id || ДА || '''ДА''' ||
    234 || FD11: transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id || transaction_id || ДА || '''ДА''' ||
     202|| FD8: holding_id → holding_quantity, avg_price, portfolio_id, stock_id || holding_id || ДА || '''ДА''' ||
     203|| FD9: history_id → history_price, history_timestamp, stock_id || history_id || ДА || '''ДА''' ||
     204|| FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id, portfolio_id || trade_id || ДА || '''ДА''' ||
     205|| FD11: transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id, trade_request_id || transaction_id || ДА || '''ДА''' ||
    235206|| FD12: watchlist_id → price_above, price_below, user_id, stock_id || watchlist_id || ДА || '''ДА''' ||
    236 || FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id || oauth_token || ДА || '''ДА''' ||
    237 || FD1-FD7: транзитивни преку горните детерминанти || не директно || НЕ || Не директно ||
     207|| FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id, oauth_auth_provider_id || oauth_token || ДА || '''ДА''' ||
     208|| FD14: auth_provider_id → auth_provider || auth_provider_id || НЕ || Не парцијална зависност ||
    238209
    239210Ги елиминираме по ред, почнувајќи со FD8.
     
    248219   FK: portfolio_id → Portfolios, stock_id → Stock
    249220
    250 Universal_Relation_Base_1 = Universal_Relation_Base - {holding_id, holding_quantity, avg_price}
     221Universal_Relation_Base_1 = Universal_Relation_TradingMK - {holding_id, holding_quantity, avg_price}
    251222   PK: {history_id, trade_id, transaction_id, watchlist_id, oauth_token}
    252223}}}
     
    285256=== Чекор 2.3: Декомпозиција по FD10 (trade_id → ...) ===
    286257
    287 '''Нарушува 2NF:''' trade_id е дел од PK, а trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol, portfolio_id зависат само од него.
     258'''Нарушува 2NF:''' trade_id е дел од PK, а trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id, portfolio_id зависат само од него.
    288259
    289260{{{
    290261Trade_Request(trade_id, trade_type, trade_status, trade_quantity, price_per_unit,
    291               trade_timestamp, trade_stock_symbol, portfolio_id)
     262              trade_timestamp, trade_stock_id, portfolio_id)
    292263   PK: trade_id
    293    FK: portfolio_id → Portfolios
     264   FK: portfolio_id → Portfolios, trade_stock_id → Stock
    294265
    295266Universal_Relation_Base_3 = Universal_Relation_Base_2 - {trade_id, trade_type, trade_status,
    296                              trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol}
     267                             trade_quantity, price_per_unit, trade_timestamp, trade_stock_id}
    297268   PK: {transaction_id, watchlist_id, oauth_token}
    298269}}}
    299270
    300 '''FD во Trade_Request:''' FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_symbol, portfolio_id
     271'''FD во Trade_Request:''' FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id, portfolio_id
    301272
    302273'''Кандидат клучеви:''' {trade_id}
     
    310281=== Чекор 2.4: Декомпозиција по FD11 (transaction_id → ...) ===
    311282
    312 '''Нарушува 2NF:''' transaction_id е дел од PK, а txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id зависат само од него.
     283'''Нарушува 2NF:''' transaction_id е дел од PK, а txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id, trade_request_id зависат само од него.
    313284
    314285{{{
    315286Transactions(transaction_id, txn_type, txn_quantity, txn_price, txn_timestamp,
    316              txn_origin, user_id, stock_id)
     287             txn_origin, user_id, stock_id, trade_request_id)
    317288   PK: transaction_id
    318    FK: user_id → Users, stock_id → Stock
     289   FK: user_id → Users, stock_id → Stock, trade_request_id → Trade_Request
    319290
    320291Universal_Relation_Base_4 = Universal_Relation_Base_3 - {transaction_id, txn_type, txn_quantity,
    321                              txn_price, txn_timestamp, txn_origin}
     292                             txn_price, txn_timestamp, txn_origin, trade_request_id}
    322293   PK: {watchlist_id, oauth_token}
    323294}}}
    324295
    325 '''FD во Transactions:''' FD11: transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id
     296'''FD во Transactions:''' FD11: transaction_id → txn_type, txn_quantity, txn_price, txn_timestamp, txn_origin, user_id, stock_id, trade_request_id
    326297
    327298'''Кандидат клучеви:''' {transaction_id}
     
    356327=== Чекор 2.6: Декомпозиција по FD13 (oauth_token → ...) ===
    357328
    358 '''Нарушува 2NF:''' oauth_token е дел од PK, а oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id зависат само од него.
     329'''Нарушува 2NF:''' oauth_token е дел од PK, а oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id, oauth_auth_provider_id зависат само од него.
    359330
    360331{{{
    361332OAuth_Pending_Links(oauth_token, oauth_email, oauth_provider, oauth_expires_at,
    362                     oauth_created_at, user_id)
     333                    oauth_created_at, user_id, oauth_auth_provider_id)
    363334   PK: oauth_token
    364    FK: user_id → Users
     335   FK: user_id → Users, oauth_auth_provider_id → AuthProvider
    365336
    366337Universal_Relation_Base_6 = Universal_Relation_Base_5 - {oauth_token, oauth_email,
    367                              oauth_provider, oauth_expires_at, oauth_created_at}
     338                             oauth_provider, oauth_expires_at, oauth_created_at, oauth_auth_provider_id}
    368339   Останати атрибути:
    369340   (user_id, username, password, email, role,
     341    auth_provider_id, auth_provider,
    370342    portfolio_id, balance,
    371343    stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated)
     
    373345}}}
    374346
    375 '''FD во OAuth_Pending_Links:''' FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id
     347'''FD во OAuth_Pending_Links:''' FD13: oauth_token → oauth_email, oauth_provider, oauth_expires_at, oauth_created_at, user_id, oauth_auth_provider_id
    376348
    377349'''Кандидат клучеви:''' {oauth_token}
     
    381353'''Dependency preservation:''' FD13 е зачувана во OAuth_Pending_Links. ✓
    382354
     355=== Чекор 2.7: Декомпозиција по FD14 (auth_provider_id → auth_provider) ===
     356
     357'''FD14:''' auth_provider_id → auth_provider
     358
     359Бидејќи auth_provider_id не е дел од примарниот клуч на Universal_Relation_Base_6, FD14 не претставува парцијална зависност и се обработува во 3NF како зависност од независен ентитет.
     360
     361----
     362
    383363=== Состојба после 2NF декомпозиција ===
    384364
    385 По извлекувањето на сите парцијални зависности, останатата релација Universal_Relation_Base_6 содржи три независни ентитети:
     365По извлекувањето на сите парцијални зависности, останатата релација Universal_Relation_Base_6 содржи независни ентитети:
    386366
    387367{{{
    388368Universal_Relation_Base_6(
    389369  user_id, username, password, email, role,
     370  auth_provider_id, auth_provider,
    390371  portfolio_id, balance,
    391372  stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated
     
    394375}}}
    395376
    396 Оваа релација веќе нема парцијални зависности, па продолжуваме директно со проверка за 3NF. Меѓутоа, содржи транзитивни зависности - нарушување на 3NF.
     377Оваа релација веќе нема парцијални зависности, па продолжуваме директно со проверка за 3NF. Меѓутоа, содржи транзитивни зависности и независни ентитети - нарушување на 3NF.
    397378
    398379{{{
    399380Состојба по 2NF:
    400381
    401 User_Auth_Providers(user_id, auth_provider)                 — од 1NF
    402382Portfolio_Holdings(holding_id, holding_quantity, avg_price, portfolio_id, stock_id)
    403383Stock_History(history_id, history_price, history_timestamp, stock_id)
    404384Trade_Request(trade_id, trade_type, trade_status, trade_quantity, price_per_unit,
    405               trade_timestamp, trade_stock_symbol, portfolio_id)
     385              trade_timestamp, trade_stock_id, portfolio_id)
    406386Transactions(transaction_id, txn_type, txn_quantity, txn_price, txn_timestamp,
    407              txn_origin, user_id, stock_id)
     387             txn_origin, user_id, stock_id, trade_request_id)
    408388Watchlist(watchlist_id, price_above, price_below, user_id, stock_id)
    409389OAuth_Pending_Links(oauth_token, oauth_email, oauth_provider, oauth_expires_at,
    410                     oauth_created_at, user_id)
     390                    oauth_created_at, user_id, oauth_auth_provider_id)
    411391Universal_Relation_Base_6(user_id, username, password, email, role,
     392                           auth_provider_id, auth_provider,
    412393                           portfolio_id, balance,
    413394                           stock_id, stock_symbol, stock_name, current_price, last_price,
     
    421402=== Дефиниција ===
    422403
    423 Релацијата е во 3NF ако е во 2NF и за секоја нетривијална FD X → A, или X е суперклуч, или A е примарен атрибут. Ова ги елиминира транзитивните зависности. prov
     404Релацијата е во 3NF ако е во 2NF и за секоја нетривијална FD X → A, или X е суперклуч, или A е примарен атрибут. Ова ги елиминира транзитивните зависности.
    424405
    425406=== Анализа на Universal_Relation_Base_6 ===
     
    427408'''Анализирана релација:''' Universal_Relation_Base_6
    428409
    429 '''Применети FD:''' FD1, FD2, FD3, FD4, FD5, FD6, FD7
    430 
    431 '''Нормална форма:''' НЕ е во 3NF. Постои транзитивна зависност: user_id → portfolio_id → balance (balance е транзитивно зависен од user_id преку portfolio_id). Stock атрибутите се целосно независни од User атрибутите.
    432 
    433 '''Зависности кои предизвикуваат проблем:'''
    434  * Транзитивна зависност: user_id → portfolio_id → balance (balance зависи транзитивно од user_id преку portfolio_id кој не е PK во оваа релација)
    435  * FD6 и FD7 формираат независен ентитет (Stock) кој не е функционално поврзан со User или Portfolio во оваа релација - мора да се извлече посебно
     410'''Применети FD:''' FD1, FD2, FD3, FD4, FD5, FD6, FD7, FD14
     411
     412'''Нормална форма:''' НЕ е во 3NF. Постои транзитивна зависност: user_id → portfolio_id → balance (balance е транзитивно зависен од user_id преку portfolio_id кој не е PK во оваа релација).
     413
     414Исто така, постои зависност auth_provider_id → auth_provider, каде auth_provider_id претставува идентификатор на независен AuthProvider ентитет и затоа AuthProvider мора да се извлече во посебна релација.
     415
     416Stock атрибутите се целосно независни од User и Portfolio атрибутите и мора да се извлечат како посебен ентитет.
     417
     418'''Зависности кои го предизвикуваат проблемот:'''
     419 * Транзитивна зависност: user_id → portfolio_id → balance
     420 * FD14: auth_provider_id → auth_provider
     421 * FD6 и FD7 формираат независен ентитет (Stock) кој не е функционално поврзан со User или Portfolio во оваа релација
    436422
    437423=== Чекор 3.1: Декомпозиција по FD1/FD2/FD3 (user_id → ...) ===
     
    486472Universal_Relation_Base_9 = Universal_Relation_Base_8 - {stock_id, stock_symbol, stock_name,
    487473                             current_price, last_price, percentage, turnover, last_updated}
    488    = ∅  (сите атрибути се распоредени)
    489474}}}
    490475
     
    495480'''Нормална форма на Stock:''' 3NF - двата детерминанти (stock_id и stock_symbol) се кандидат клучеви. ✓
    496481
    497 '''Lossless join:''' Заедничкиот атрибут stock_id - lossless. 
     482'''Lossless join:''' Заедничкиот атрибут stock_id - lossless.
    498483
    499484'''Dependency preservation:''' FD6, FD7 зачувани. ✓
    500485
    501 Universal_Relation_Base_9 е празна (∅) - сите атрибути се успешно распоредени.
     486=== Чекор 3.4: Декомпозиција по FD14 (auth_provider_id → auth_provider) ===
     487
     488{{{
     489AuthProvider(auth_provider_id, auth_provider)
     490   PK: auth_provider_id
     491   Кандидат клучеви: {auth_provider_id}, {auth_provider}
     492
     493Universal_Relation_Base_10 = Universal_Relation_Base_9 - {auth_provider_id, auth_provider}
     494   = ∅
     495}}}
     496
     497'''FD во AuthProvider:''' FD14: auth_provider_id → auth_provider
     498
     499'''Кандидат клучеви:''' {auth_provider_id}, {auth_provider}
     500
     501'''Нормална форма на AuthProvider:''' 3NF - auth_provider_id е примарен клуч, а auth_provider е кандидат клуч. ✓
     502
     503'''Lossless join:''' Заедничкиот атрибут auth_provider_id е PK во AuthProvider - lossless. ✓
     504
     505'''Dependency preservation:''' FD14 е зачувана. ✓
     506
     507Universal_Relation_Base_10 е празна (∅) - сите атрибути се успешно распоредени.
    502508
    503509=== Проверка за транзитивни зависности во сите релации ===
    504510
    505511||= Релација =||= Проверка =||= 3NF? =||
    506 || User_Auth_Providers || Нема не-клучни атрибути - само PK || ✓ ДА ||
    507512|| Portfolio_Holdings || holding_id → сите; portfolio_id и stock_id не одредуваат меѓусебно никој не-клучен атрибут || ✓ ДА ||
    508513|| Stock_History || history_id → сите; stock_id не одредува history_price/timestamp во оваа релација || ✓ ДА ||
     
    514519|| Portfolios || portfolio_id, user_id - сите се кандидат клучеви → без транзитивност || ✓ ДА ||
    515520|| Stock || stock_id, stock_symbol - сите се кандидат клучеви → без транзитивност || ✓ ДА ||
     521|| AuthProvider || auth_provider_id, auth_provider - сите се кандидат клучеви → без транзитивност || ✓ ДА ||
    516522
    517523'''Заклучок:''' Сите 10 релации се во 3NF. ✓
     
    554560'''Stock е во BCNF ✓'''
    555561
    556 ==== Останати 7 релации ====
    557 
    558 User_Auth_Providers, Portfolio_Holdings, Stock_History, Trade_Request, Transactions, Watchlist, OAuth_Pending_Links - секоја има точно еден кандидат клуч. Единствената нетривијална FD го има PK-от како детерминант.
     562==== AuthProvider - Кандидат клучеви: {auth_provider_id}, {auth_provider} ====
     563
     564||= FD =||= Детерминант =||= Суперклуч? =||
     565|| auth_provider_id → auth_provider || auth_provider_id || ✓ ДА ||
     566|| auth_provider → auth_provider_id || auth_provider || ✓ ДА ||
     567
     568'''AuthProvider е во BCNF ✓'''
     569
     570==== Останати релации ====
     571
     572Portfolio_Holdings, Stock_History, Trade_Request, Transactions, Watchlist, OAuth_Pending_Links - секоја има точно еден кандидат клуч. Единствената нетривијална FD го има PK-от како детерминант.
    559573
    560574'''Сите се во BCNF ✓'''
     
    574588  - Надворешни клучеви: -
    575589
    576 User_Auth_Providers(user_id, auth_provider)
    577   - Примарен клуч:    {user_id, auth_provider}
    578   - Кандидат клучеви: {user_id, auth_provider}
    579   - Надворешни клучеви: user_id → Users
     590AuthProvider(auth_provider_id, auth_provider)
     591  - Примарен клуч:    auth_provider_id
     592  - Кандидат клучеви: {auth_provider_id}, {auth_provider}
     593  - Надворешни клучеви: -
    580594
    581595Portfolios(portfolio_id, balance, user_id)
     
    603617
    604618Trade_Request(trade_id, trade_type, trade_status, trade_quantity, price_per_unit,
    605               trade_timestamp, trade_stock_symbol, portfolio_id)
     619              trade_timestamp, trade_stock_id, portfolio_id)
    606620  - Примарен клуч:    trade_id
    607621  - Кандидат клучеви: {trade_id}
    608   - Надворешни клучеви: portfolio_id → Portfolios
     622  - Надворешни клучеви: portfolio_id → Portfolios, trade_stock_id → Stock
    609623  - Напомена: user_id е изводливо преку portfolio_id → Portfolios → Users
    610624
    611625Transactions(transaction_id, txn_type, txn_quantity, txn_price, txn_timestamp,
    612              txn_origin, user_id, stock_id)
     626             txn_origin, user_id, stock_id, trade_request_id)
    613627  - Примарен клуч:    transaction_id
    614628  - Кандидат клучеви: {transaction_id}
    615   - Надворешни клучеви: user_id → Users, stock_id → Stock
     629  - Надворешни клучеви: user_id → Users, stock_id → Stock,
     630                        trade_request_id → Trade_Request
    616631
    617632Watchlist(watchlist_id, price_above, price_below, user_id, stock_id)
     
    620635  - Надворешни клучеви: user_id → Users, stock_id → Stock
    621636  - Напомена: (user_id, stock_id) НЕ е уникатен - еден корисник може да има
    622               повеќе alerт-ови за иста акција
     637              повеќе alert-ови за иста акција
    623638
    624639OAuth_Pending_Links(oauth_token, oauth_email, oauth_provider, oauth_expires_at,
    625                     oauth_created_at, user_id)
     640                    oauth_created_at, user_id, oauth_auth_provider_id)
    626641  - Примарен клуч:    oauth_token
    627642  - Кандидат клучеви: {oauth_token}
    628   - Надворешни клучеви: user_id → Users
     643  - Надворешни клучеви: user_id → Users,
     644                        oauth_auth_provider_id → AuthProvider
    629645}}}
    630646
     
    637653 2. '''Декомпозицијата е lossless''' - на секој чекор оригиналната информација може да се реконструира преку JOIN операции на заедничките атрибути (надворешни клучеви). Ова е гарантирано со Heath теоремата, бидејќи секоја декомпозиција се врши по FD чиј детерминант е клуч во новата релација.
    638654
    639  3. '''Сите функционални зависности се зачувани''' - сите 13 функционални зависности (FD1-FD13) се зачувани во соодветните релации, без потреба за скапи JOIN операции при проверка на ограничувањата.
     655 3. '''Сите функционални зависности се зачувани''' - сите 14 функционални зависности (FD1-FD14) се зачувани во соодветните релации, без потреба за скапи JOIN операции при проверка на ограничувањата.
    640656
    641657
     
    644660Финалниот нормализиран дизајн (Фаза P5) ќе се користи во сите понатамошни фази на проектот. Тој е идентичен со дизајнот од Фаза P2 со следните конкретни измени во имплементацијата:
    645661 * Додавање на UNIQUE ограничувачи на stock.symbol
    646 
     662 * Додавање на релација помеѓу Trade_Request и Stock преку stock_id
     663 * Додавање на релација помеѓу Transactions и Trade_Request преку trade_request_id
     664 * Додавање на релација помеѓу OAuth_Pending_Links и AuthProvider преку auth_provider_id