Changes between Version 6 and Version 7 of Normalization
- Timestamp:
- 08/29/26 01:17:39 (2 weeks ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Normalization
v6 v7 10 10 Universal_Relation_TradingMK( 11 11 user_id, username, password, email, role, 12 auth_provider ,12 auth_provider_id, auth_provider, 13 13 portfolio_id, balance, 14 14 holding_id, holding_quantity, avg_price, 15 15 stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated, 16 16 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, 19 19 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 21 21 ) 22 22 }}} 23 23 24 24 '''Напомени за именување:''' 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 во универзалната релација 27 28 * Нема дупликати на имиња на атрибути во универзалната релација 28 29 … … 41 42 * '''FD8:''' holding_id → holding_quantity, avg_price, portfolio_id, stock_id 42 43 * '''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_id44 * '''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 45 46 * '''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 47 49 '''}''' 48 50 … … 59 61 || email || ✓ (FD3) || ✓ (FD1) || и лево и десно || 60 62 || role || ✗ || ✓ (FD1) || само десно || 61 || auth_provider || ✗ || ✗ || '''не се јавува во ниедна FD''' || 63 || auth_provider_id || ✓ (FD14) || ✓ (FD13) || и лево и десно || 64 || auth_provider || ✗ || ✓ (FD14) || само десно || 62 65 || portfolio_id || ✓ (FD4) || ✓ (FD5, FD8, FD10) || и лево и десно || 63 66 || balance || ✗ || ✓ (FD4) || само десно || … … 82 85 || price_per_unit || ✗ || ✓ (FD10) || само десно || 83 86 || trade_timestamp || ✗ || ✓ (FD10) || само десно || 84 || trade_stock_ symbol|| ✗ || ✓ (FD10) || само десно ||87 || trade_stock_id || ✗ || ✓ (FD10) || само десно || 85 88 || transaction_id || ✓ (FD11) || ✗ || '''само лево''' || 86 89 || txn_type || ✗ || ✓ (FD11) || само десно || … … 89 92 || txn_timestamp || ✗ || ✓ (FD11) || само десно || 90 93 || txn_origin || ✗ || ✓ (FD11) || само десно || 94 || trade_request_id || ✗ || ✓ (FD11) || само десно || 91 95 || watchlist_id || ✓ (FD12) || ✗ || '''само лево''' || 92 96 || price_above || ✗ || ✓ (FD12) || само десно || … … 97 101 || oauth_expires_at || ✗ || ✓ (FD13) || само десно || 98 102 || oauth_created_at || ✗ || ✓ (FD13) || само десно || 103 || oauth_auth_provider_id || ✗ || ✓ (FD13) || само десно || 99 104 100 105 ==== Атрибути кои се појавуваат САМО на лева страна ==== … … 108 113 * '''watchlist_id''' - мора да биде дел од секој кандидат клуч 109 114 * '''oauth_token''' - мора да биде дел од секој кандидат клуч 110 * '''auth_provider''' - мора да биде дел од секој кандидат клуч (не учествува во ниедна FD; изводливо само преку себе)111 115 112 116 ==== Пресметка на затворач ==== … … 115 119 116 120 {{{ 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}: 118 122 119 123 - Од FD8 (holding_id →): holding_quantity, avg_price, portfolio_id, stock_id 120 124 - Од FD9 (history_id →): history_price, history_timestamp, stock_id 121 125 - Од FD10 (trade_id →): trade_type, trade_status, trade_quantity, price_per_unit, 122 trade_timestamp, trade_stock_ symbol, portfolio_id123 - Од 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 125 129 - Од 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 127 132 - Од FD4 (portfolio_id →): balance, user_id 128 133 - Од FD5 (user_id →): portfolio_id … … 133 138 - Од FD2 (username →): user_id 134 139 - Од 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} 139 145 = Universal_Relation_TradingMK ✓ (сите атрибути се изводливи) 140 146 }}} … … 146 152 || без holding_id || holding_quantity, avg_price || ✗ НЕ || 147 153 || без 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 || ✗ НЕ || 150 156 || без 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 || ✗ НЕ || 153 158 154 159 Секој атрибут е неопходен - множеството е минимално. … … 159 164 160 165 {{{ 161 PK = {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token , auth_provider}162 }}} 163 164 '''Образложение:''' Примарниот клуч е голем бидејќи универзалната релација содржи повеќе независни ентитети (корисници, портфолија, акции, трговски барања, трансакции, watchlist записи, OAuth токени ,auth провајдери) кои не се директно поврзани преку функционални зависности. Секој независен ентитет бара барем еден идентификатор во клучот. Клучот е минимален - отстранувањето на кој било атрибут го прави невозможно изведувањето на дел од атрибутите.166 PK = {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token} 167 }}} 168 169 '''Образложение:''' Примарниот клуч е голем бидејќи универзалната релација содржи повеќе независни ентитети (корисници, портфолија, акции, трговски барања, трансакции, watchlist записи, OAuth токени и auth провајдери) кои не се директно поврзани преку функционални зависности. Секој независен ентитет бара барем еден идентификатор во клучот. Клучот е минимален - отстранувањето на кој било атрибут го прави невозможно изведувањето на дел од атрибутите. 165 170 166 171 ==== Нормална форма пред декомпозиција ==== 167 172 168 Universal_Relation_TradingMK е во '''1NF''' (сите атрибути се атомарни, со исклучок на auth_provider кој е мулти-вредносен). Релацијата '''НЕ е во 2NF''' поради следните парцијални зависности - секој идентификатор ги определува само своите атрибути, независно од останатиот примарен клуч: 173 Universal_Relation_TradingMK е во '''1NF''' бидејќи сите атрибути се атомарни. AuthProvider е моделиран како посебен ентитет преку auth_provider_id, па auth_provider повеќе не е мулти-вредносен атрибут во универзалната релација. 174 175 Релацијата '''НЕ е во 2NF''' поради следните парцијални зависности - секој идентификатор ги определува само своите атрибути, независно од останатиот примарен клуч: 169 176 170 177 * FD8: holding_id → holding_quantity, avg_price, portfolio_id, stock_id 171 178 * FD9: history_id → history_price, history_timestamp, stock_id 172 179 * 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 174 181 * 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 176 184 177 185 ---- 178 186 179 == 1NF Декомпозиција == 187 == 2NF Декомпозиција == 188 189 === Дефиниција === 190 191 Релацијата е во 2NF ако е во 1NF и секој не-клучен атрибут целосно функционално зависи од целиот примарен клуч - нема парцијални зависности. 180 192 181 193 === Анализа === … … 183 195 '''Анализирана релација:''' Universal_Relation_TradingMK 184 196 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 → Users198 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_Base225 226 197 '''Примарен клуч:''' {holding_id, history_id, trade_id, transaction_id, watchlist_id, oauth_token} 227 198 … … 229 200 230 201 ||= 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 || ДА || '''ДА''' || 235 206 || 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 || НЕ || Не парцијална зависност || 238 209 239 210 Ги елиминираме по ред, почнувајќи со FD8. … … 248 219 FK: portfolio_id → Portfolios, stock_id → Stock 249 220 250 Universal_Relation_Base_1 = Universal_Relation_ Base- {holding_id, holding_quantity, avg_price}221 Universal_Relation_Base_1 = Universal_Relation_TradingMK - {holding_id, holding_quantity, avg_price} 251 222 PK: {history_id, trade_id, transaction_id, watchlist_id, oauth_token} 252 223 }}} … … 285 256 === Чекор 2.3: Декомпозиција по FD10 (trade_id → ...) === 286 257 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 зависат само од него. 288 259 289 260 {{{ 290 261 Trade_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) 292 263 PK: trade_id 293 FK: portfolio_id → Portfolios 264 FK: portfolio_id → Portfolios, trade_stock_id → Stock 294 265 295 266 Universal_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} 297 268 PK: {transaction_id, watchlist_id, oauth_token} 298 269 }}} 299 270 300 '''FD во Trade_Request:''' FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_ symbol, portfolio_id271 '''FD во Trade_Request:''' FD10: trade_id → trade_type, trade_status, trade_quantity, price_per_unit, trade_timestamp, trade_stock_id, portfolio_id 301 272 302 273 '''Кандидат клучеви:''' {trade_id} … … 310 281 === Чекор 2.4: Декомпозиција по FD11 (transaction_id → ...) === 311 282 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 зависат само од него. 313 284 314 285 {{{ 315 286 Transactions(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) 317 288 PK: transaction_id 318 FK: user_id → Users, stock_id → Stock 289 FK: user_id → Users, stock_id → Stock, trade_request_id → Trade_Request 319 290 320 291 Universal_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} 322 293 PK: {watchlist_id, oauth_token} 323 294 }}} 324 295 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 326 297 327 298 '''Кандидат клучеви:''' {transaction_id} … … 356 327 === Чекор 2.6: Декомпозиција по FD13 (oauth_token → ...) === 357 328 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 зависат само од него. 359 330 360 331 {{{ 361 332 OAuth_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) 363 334 PK: oauth_token 364 FK: user_id → Users 335 FK: user_id → Users, oauth_auth_provider_id → AuthProvider 365 336 366 337 Universal_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} 368 339 Останати атрибути: 369 340 (user_id, username, password, email, role, 341 auth_provider_id, auth_provider, 370 342 portfolio_id, balance, 371 343 stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated) … … 373 345 }}} 374 346 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 376 348 377 349 '''Кандидат клучеви:''' {oauth_token} … … 381 353 '''Dependency preservation:''' FD13 е зачувана во OAuth_Pending_Links. ✓ 382 354 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 383 363 === Состојба после 2NF декомпозиција === 384 364 385 По извлекувањето на сите парцијални зависности, останатата релација Universal_Relation_Base_6 содржи тринезависни ентитети:365 По извлекувањето на сите парцијални зависности, останатата релација Universal_Relation_Base_6 содржи независни ентитети: 386 366 387 367 {{{ 388 368 Universal_Relation_Base_6( 389 369 user_id, username, password, email, role, 370 auth_provider_id, auth_provider, 390 371 portfolio_id, balance, 391 372 stock_id, stock_symbol, stock_name, current_price, last_price, percentage, turnover, last_updated … … 394 375 }}} 395 376 396 Оваа релација веќе нема парцијални зависности, па продолжуваме директно со проверка за 3NF. Меѓутоа, содржи транзитивни зависности - нарушување на 3NF.377 Оваа релација веќе нема парцијални зависности, па продолжуваме директно со проверка за 3NF. Меѓутоа, содржи транзитивни зависности и независни ентитети - нарушување на 3NF. 397 378 398 379 {{{ 399 380 Состојба по 2NF: 400 381 401 User_Auth_Providers(user_id, auth_provider) — од 1NF402 382 Portfolio_Holdings(holding_id, holding_quantity, avg_price, portfolio_id, stock_id) 403 383 Stock_History(history_id, history_price, history_timestamp, stock_id) 404 384 Trade_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) 406 386 Transactions(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) 408 388 Watchlist(watchlist_id, price_above, price_below, user_id, stock_id) 409 389 OAuth_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) 411 391 Universal_Relation_Base_6(user_id, username, password, email, role, 392 auth_provider_id, auth_provider, 412 393 portfolio_id, balance, 413 394 stock_id, stock_symbol, stock_name, current_price, last_price, … … 421 402 === Дефиниција === 422 403 423 Релацијата е во 3NF ако е во 2NF и за секоја нетривијална FD X → A, или X е суперклуч, или A е примарен атрибут. Ова ги елиминира транзитивните зависности. prov404 Релацијата е во 3NF ако е во 2NF и за секоја нетривијална FD X → A, или X е суперклуч, или A е примарен атрибут. Ова ги елиминира транзитивните зависности. 424 405 425 406 === Анализа на Universal_Relation_Base_6 === … … 427 408 '''Анализирана релација:''' Universal_Relation_Base_6 428 409 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 416 Stock атрибутите се целосно независни од User и Portfolio атрибутите и мора да се извлечат како посебен ентитет. 417 418 '''Зависности кои го предизвикуваат проблемот:''' 419 * Транзитивна зависност: user_id → portfolio_id → balance 420 * FD14: auth_provider_id → auth_provider 421 * FD6 и FD7 формираат независен ентитет (Stock) кој не е функционално поврзан со User или Portfolio во оваа релација 436 422 437 423 === Чекор 3.1: Декомпозиција по FD1/FD2/FD3 (user_id → ...) === … … 486 472 Universal_Relation_Base_9 = Universal_Relation_Base_8 - {stock_id, stock_symbol, stock_name, 487 473 current_price, last_price, percentage, turnover, last_updated} 488 = ∅ (сите атрибути се распоредени)489 474 }}} 490 475 … … 495 480 '''Нормална форма на Stock:''' 3NF - двата детерминанти (stock_id и stock_symbol) се кандидат клучеви. ✓ 496 481 497 '''Lossless join:''' Заедничкиот атрибут stock_id - lossless. 482 '''Lossless join:''' Заедничкиот атрибут stock_id - lossless. 498 483 499 484 '''Dependency preservation:''' FD6, FD7 зачувани. ✓ 500 485 501 Universal_Relation_Base_9 е празна (∅) - сите атрибути се успешно распоредени. 486 === Чекор 3.4: Декомпозиција по FD14 (auth_provider_id → auth_provider) === 487 488 {{{ 489 AuthProvider(auth_provider_id, auth_provider) 490 PK: auth_provider_id 491 Кандидат клучеви: {auth_provider_id}, {auth_provider} 492 493 Universal_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 507 Universal_Relation_Base_10 е празна (∅) - сите атрибути се успешно распоредени. 502 508 503 509 === Проверка за транзитивни зависности во сите релации === 504 510 505 511 ||= Релација =||= Проверка =||= 3NF? =|| 506 || User_Auth_Providers || Нема не-клучни атрибути - само PK || ✓ ДА ||507 512 || Portfolio_Holdings || holding_id → сите; portfolio_id и stock_id не одредуваат меѓусебно никој не-клучен атрибут || ✓ ДА || 508 513 || Stock_History || history_id → сите; stock_id не одредува history_price/timestamp во оваа релација || ✓ ДА || … … 514 519 || Portfolios || portfolio_id, user_id - сите се кандидат клучеви → без транзитивност || ✓ ДА || 515 520 || Stock || stock_id, stock_symbol - сите се кандидат клучеви → без транзитивност || ✓ ДА || 521 || AuthProvider || auth_provider_id, auth_provider - сите се кандидат клучеви → без транзитивност || ✓ ДА || 516 522 517 523 '''Заклучок:''' Сите 10 релации се во 3NF. ✓ … … 554 560 '''Stock е во BCNF ✓''' 555 561 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 572 Portfolio_Holdings, Stock_History, Trade_Request, Transactions, Watchlist, OAuth_Pending_Links - секоја има точно еден кандидат клуч. Единствената нетривијална FD го има PK-от како детерминант. 559 573 560 574 '''Сите се во BCNF ✓''' … … 574 588 - Надворешни клучеви: - 575 589 576 User_Auth_Providers(user_id, auth_provider)577 - Примарен клуч: {user_id, auth_provider}578 - Кандидат клучеви: { user_id,auth_provider}579 - Надворешни клучеви: user_id → Users590 AuthProvider(auth_provider_id, auth_provider) 591 - Примарен клуч: auth_provider_id 592 - Кандидат клучеви: {auth_provider_id}, {auth_provider} 593 - Надворешни клучеви: - 580 594 581 595 Portfolios(portfolio_id, balance, user_id) … … 603 617 604 618 Trade_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) 606 620 - Примарен клуч: trade_id 607 621 - Кандидат клучеви: {trade_id} 608 - Надворешни клучеви: portfolio_id → Portfolios 622 - Надворешни клучеви: portfolio_id → Portfolios, trade_stock_id → Stock 609 623 - Напомена: user_id е изводливо преку portfolio_id → Portfolios → Users 610 624 611 625 Transactions(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) 613 627 - Примарен клуч: transaction_id 614 628 - Кандидат клучеви: {transaction_id} 615 - Надворешни клучеви: user_id → Users, stock_id → Stock 629 - Надворешни клучеви: user_id → Users, stock_id → Stock, 630 trade_request_id → Trade_Request 616 631 617 632 Watchlist(watchlist_id, price_above, price_below, user_id, stock_id) … … 620 635 - Надворешни клучеви: user_id → Users, stock_id → Stock 621 636 - Напомена: (user_id, stock_id) НЕ е уникатен - еден корисник може да има 622 повеќе aler т-ови за иста акција637 повеќе alert-ови за иста акција 623 638 624 639 OAuth_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) 626 641 - Примарен клуч: oauth_token 627 642 - Кандидат клучеви: {oauth_token} 628 - Надворешни клучеви: user_id → Users 643 - Надворешни клучеви: user_id → Users, 644 oauth_auth_provider_id → AuthProvider 629 645 }}} 630 646 … … 637 653 2. '''Декомпозицијата е lossless''' - на секој чекор оригиналната информација може да се реконструира преку JOIN операции на заедничките атрибути (надворешни клучеви). Ова е гарантирано со Heath теоремата, бидејќи секоја декомпозиција се врши по FD чиј детерминант е клуч во новата релација. 638 654 639 3. '''Сите функционални зависности се зачувани''' - сите 1 3 функционални зависности (FD1-FD13) се зачувани во соодветните релации, без потреба за скапи JOIN операции при проверка на ограничувањата.655 3. '''Сите функционални зависности се зачувани''' - сите 14 функционални зависности (FD1-FD14) се зачувани во соодветните релации, без потреба за скапи JOIN операции при проверка на ограничувањата. 640 656 641 657 … … 644 660 Финалниот нормализиран дизајн (Фаза P5) ќе се користи во сите понатамошни фази на проектот. Тој е идентичен со дизајнот од Фаза P2 со следните конкретни измени во имплементацијата: 645 661 * Додавање на 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
