Changes between Version 20 and Version 21 of Normalization
- Timestamp:
- 08/06/26 12:36:16 (34 hours ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Normalization
v20 v21 6 6 7 7 {{{ 8 Universal_Relation_Shifter( 9 user_id, user_name, user_email, user_login_provider, user_password_hash, user_ verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, user_course_favorite_ids,8 Universal_Relation_Shifter( account_id, account_email, account_password_hash, account_name, 9 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, user_favorite_course_ids, 10 10 meeting_reminder_id, meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, 11 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash, 11 expert_id, 12 language_id, language_value, 12 13 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 13 course_version_id, version_number, version_creat ion_date, version_active,14 course_version_id, version_number, version_created_at, version_is_active, 14 15 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 15 16 payment_id, payment_amount, payment_date, payment_method, payment_status, 16 17 review_id, review_rating, review_comment, review_date, 17 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,18 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 18 19 course_what_will_be_learned, 19 20 course_content_id, content_position, 20 course_content_translate_id, content_translate_title, content_translate_language,21 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 22 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,23 user_course_progress_id, progress_ completed, progress_completed_at,24 verification_token_uuid, token_created_at, token_expire d_at,21 course_content_translate_id, content_translate_title, 22 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 23 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 24 user_course_progress_id, progress_is_completed, progress_completed_at, 25 verification_token_uuid, token_created_at, token_expires_at, 25 26 tag_id, tag_type, 26 tag_translate_id, tag_translate_language, tag_value 27 ) 28 }}} 27 tag_translate_id, tag_value ) 28 }}} 29 30 '''Забелешка за јазикот:''' Во претходната верзија секоја релација за превод носеше сопствен атрибут за јазик (course_translate_language, content_translate_language, lecture_language, tag_translate_language). Во новиот модел јазикот е самостоен ентитет (Language), па сите четири релации за превод упатуваат кон истиот атрибут language_id. Во универзалната релација тоа значи дека една торка ги содржи преводите на еден ист јазик. 31 32 '''Забелешка за сметките:''' Атрибутите за најава (email, password_hash, name) се издвоени во ентитетот Account. Затоа Expert повеќе не носи сопствени атрибути за име и мејл, туку само упатување кон Account. 29 33 30 34 ---- … … 35 39 36 40 '''F = {''' 37 * '''FD1:''' user_id → user_name, user_email, user_login_provider, user_password_hash, user_ verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points38 * '''FD2:''' verification_token_uuid → token_created_at, token_expire d_at, user_id41 * '''FD1:''' user_id → user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, account_id 42 * '''FD2:''' verification_token_uuid → token_created_at, token_expires_at, user_id 39 43 * '''FD3:''' meeting_reminder_id → meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, user_id 40 * '''FD4:''' expert_id → expert_name, expert_email, expert_login_provider, expert_password_hash44 * '''FD4:''' expert_id → account_id 41 45 * '''FD5:''' course_id → course_image_url, course_color, course_difficulty, course_duration_minutes, course_price 42 46 * '''FD6:''' enrollment_id → enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id, payment_id, review_id … … 44 48 * '''FD8:''' review_id → review_rating, review_comment, review_date, enrollment_id 45 49 * '''FD9:''' tag_id → tag_type 46 * '''FD10:''' tag_translate_id → tag_ translate_language, tag_value, tag_id47 * '''FD11:''' course_version_id → version_number, version_creat ion_date, version_active, course_id48 * '''FD12:''' course_translate_id → course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id50 * '''FD10:''' tag_translate_id → tag_value, tag_id, language_id 51 * '''FD11:''' course_version_id → version_number, version_created_at, version_is_active, course_id 52 * '''FD12:''' course_translate_id → course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id 49 53 * '''FD13:''' course_content_id → content_position, course_version_id 50 * '''FD14:''' course_content_translate_id → content_translate_title, co ntent_translate_language, course_content_id54 * '''FD14:''' course_content_translate_id → content_translate_title, course_content_id, language_id 51 55 * '''FD15:''' course_lecture_id → lecture_duration_minutes, lecture_position, lecture_content_type, course_content_id 52 * '''FD16:''' course_lecture_translate_id → lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id53 * '''FD17:''' user_course_progress_id → progress_ completed, progress_completed_at, enrollment_id, course_lecture_id56 * '''FD16:''' course_lecture_translate_id → lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id 57 * '''FD17:''' user_course_progress_id → progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id 54 58 * '''FD18:''' user_email → user_id 55 * '''FD19:''' expert_email → expert_id59 * '''FD19:''' account_id → account_email, account_password_hash, account_name 56 60 * '''FD20:''' (course_id, version_number) → course_version_id 57 * '''FD21:''' (course_id, course_translate_language) → course_translate_id58 * '''FD22:''' (course_lecture_id, l ecture_language) → course_lecture_translate_id59 * '''FD23:''' (course_content_id, content_translate_language) → course_content_translate_id60 * '''FD24:''' (tag_id, tag_translate_language) → tag_translate_id61 * '''FD21:''' (course_id, language_id) → course_translate_id 62 * '''FD22:''' (course_lecture_id, language_id) → course_lecture_translate_id 63 * '''FD23:''' (course_content_id, language_id) → course_content_translate_id 64 * '''FD24:''' (tag_id, language_id) → tag_translate_id 61 65 * '''FD25:''' (enrollment_id, course_lecture_id) → user_course_progress_id 62 66 * '''FD26:''' (course_version_id, content_position) → course_content_id 63 67 * '''FD27:''' (course_content_id, lecture_position) → course_lecture_id 64 68 * '''FD28:''' (course_translate_id, course_what_will_be_learned) → ∅ 65 * '''FD29:''' (user_id, user_course_favorite_ids) → ∅ 69 * '''FD29:''' (user_id, user_favorite_course_ids) → ∅ 70 * '''FD30:''' account_email → account_id 71 * '''FD31:''' language_id → language_value 72 * '''FD32:''' language_value → language_id 73 * '''FD33:''' meeting_link → meeting_reminder_id 66 74 '''}''' 67 75 76 '''Забелешка:''' FD6 го содржи payment_id на десната страна бидејќи ограничувањето `uq_payment_enrollment` дозволува најмногу една наплата по запишување. FD33 произлегува од ограничувањето `uq_meeting_email_reminder_link`. FD30 произлегува од `uq_account_email`, а FD32 од `uq_language_value`. 77 68 78 ---- 69 79 … … 77 87 78 88 ||= Атрибут =||= Лева страна =||= Десна страна =||= Класификација =|| 79 || user_id || ✓ (FD1) || ✓ (FD2, FD3, FD6, FD18) || и лево и десно || 89 || account_id || ✓ (FD19) || ✓ (FD1, FD4, FD30) || и лево и десно || 90 || account_email || ✓ (FD30) || ✓ (FD19) || и лево и десно || 91 || account_password_hash || ✗ || ✓ (FD19) || десно || 92 || account_name || ✗ || ✓ (FD19) || десно || 93 || user_id || ✓ (FD1, FD29) || ✓ (FD2, FD3, FD6, FD18) || и лево и десно || 80 94 || user_name || ✗ || ✓ (FD1) || десно || 81 95 || user_email || ✓ (FD18) || ✓ (FD1) || и лево и десно || 82 96 || user_login_provider || ✗ || ✓ (FD1) || десно || 83 97 || user_password_hash || ✗ || ✓ (FD1) || десно || 84 || user_ verified || ✗ || ✓ (FD1) || десно ||85 || user_ profile_complete || ✗ || ✓ (FD1) || десно ||86 || user_ used_free_consultation || ✗ || ✓ (FD1) || десно ||98 || user_is_verified || ✗ || ✓ (FD1) || десно || 99 || user_is_profile_complete || ✗ || ✓ (FD1) || десно || 100 || user_has_used_free_consultation || ✗ || ✓ (FD1) || десно || 87 101 || user_company_size || ✗ || ✓ (FD1) || десно || 88 102 || user_work_position || ✗ || ✓ (FD1) || десно || 89 103 || user_points || ✗ || ✓ (FD1) || десно || 90 || user_ course_favorite_ids || ✓ (FD29) || ✗ || лево ||104 || user_favorite_course_ids || ✓ (FD29) || ✗ || лево || 91 105 || verification_token_uuid || ✓ (FD2) || ✗ || лево || 92 106 || token_created_at || ✗ || ✓ (FD2) || десно || 93 || token_expire d_at || ✗ || ✓ (FD2) || десно ||94 || meeting_reminder_id || ✓ (FD3) || ✗ || лево ||107 || token_expires_at || ✗ || ✓ (FD2) || десно || 108 || meeting_reminder_id || ✓ (FD3) || ✓ (FD33) || и лево и десно || 95 109 || meeting_at || ✗ || ✓ (FD3) || десно || 96 110 || meeting_scheduled_at || ✗ || ✓ (FD3) || десно || 97 111 || meeting_sent || ✗ || ✓ (FD3) || десно || 98 || meeting_link || ✗ || ✓ (FD3) || десно || 99 || expert_id || ✓ (FD4) || ✓ (FD19) || и лево и десно || 100 || expert_name || ✗ || ✓ (FD4) || десно || 101 || expert_email || ✓ (FD19) || ✓ (FD4) || и лево и десно || 102 || expert_login_provider || ✗ || ✓ (FD4) || десно || 103 || expert_password_hash || ✗ || ✓ (FD4) || десно || 112 || meeting_link || ✓ (FD33) || ✓ (FD3) || и лево и десно || 113 || expert_id || ✓ (FD4) || ✗ || лево || 114 || language_id || ✓ (FD21, FD22, FD23, FD24, FD31) || ✓ (FD10, FD12, FD14, FD16, FD32) || и лево и десно || 115 || language_value || ✓ (FD32) || ✓ (FD31) || и лево и десно || 104 116 || course_id || ✓ (FD5, FD20, FD21) || ✓ (FD11, FD12) || и лево и десно || 105 117 || course_image_url || ✗ || ✓ (FD5) || десно || … … 125 137 || tag_type || ✗ || ✓ (FD9) || десно || 126 138 || tag_translate_id || ✓ (FD10) || ✓ (FD24) || и лево и десно || 127 || tag_translate_language || ✓ (FD24) || ✓ (FD10) || и лево и десно ||128 139 || tag_value || ✗ || ✓ (FD10) || десно || 129 140 || course_version_id || ✓ (FD11, FD26) || ✓ (FD6, FD13, FD20) || и лево и десно || 130 141 || version_number || ✓ (FD20) || ✓ (FD11) || и лево и десно || 131 || version_creat ion_date|| ✗ || ✓ (FD11) || десно ||132 || version_ active || ✗ || ✓ (FD11) || десно ||142 || version_created_at || ✗ || ✓ (FD11) || десно || 143 || version_is_active || ✗ || ✓ (FD11) || десно || 133 144 || course_translate_id || ✓ (FD12) || ✓ (FD21) || и лево и десно || 134 || course_translate_language || ✓ (FD21) || ✓ (FD12) || и лево и десно ||135 145 || course_title_short || ✗ || ✓ (FD12) || десно || 136 146 || course_title || ✗ || ✓ (FD12) || десно || … … 143 153 || course_content_translate_id || ✓ (FD14) || ✓ (FD23) || и лево и десно || 144 154 || content_translate_title || ✗ || ✓ (FD14) || десно || 145 || content_translate_language || ✓ (FD23) || ✓ (FD14) || и лево и десно ||146 155 || course_lecture_id || ✓ (FD15, FD22, FD25) || ✓ (FD16, FD17, FD27) || и лево и десно || 147 156 || lecture_duration_minutes || ✗ || ✓ (FD15) || десно || … … 150 159 || course_lecture_translate_id || ✓ (FD16) || ✓ (FD22) || и лево и десно || 151 160 || lecture_title || ✗ || ✓ (FD16) || десно || 152 || lecture_language || ✓ (FD22) || ✓ (FD16) || и лево и десно ||153 161 || lecture_content_file_name || ✗ || ✓ (FD16) || десно || 154 162 || lecture_description || ✗ || ✓ (FD16) || десно || 155 163 || lecture_content_text || ✗ || ✓ (FD16) || десно || 156 164 || user_course_progress_id || ✓ (FD17) || ✓ (FD25) || и лево и десно || 157 || progress_ completed || ✗ || ✓ (FD17) || десно ||165 || progress_is_completed || ✗ || ✓ (FD17) || десно || 158 166 || progress_completed_at || ✗ || ✓ (FD17) || десно || 159 167 160 161 162 168 === 3.3 Атрибути кои се појавуваат САМО на лева страна === 163 169 164 170 * '''verification_token_uuid''' - мора да биде дел од секој кандидат клуч 165 * ''' meeting_reminder_id''' - мора да биде дел од секој кандидат клуч171 * '''expert_id''' - мора да биде дел од секој кандидат клуч 166 172 * '''course_what_will_be_learned''' - мора да биде дел од секој кандидат клуч 167 * '''user_course_favorite_ids''' - мора да биде дел од секој кандидат клуч 173 * '''user_favorite_course_ids''' - мора да биде дел од секој кандидат клуч 174 175 '''Меѓусебно зависни парови:''' Атрибутите meeting_reminder_id и meeting_link меѓусебно се определуваат (FD3 и FD33), а ниту еден друг атрибут не ги определува. Затоа точно еден од нив мора да биде дел од секој кандидат клуч; го избираме meeting_reminder_id. Истото важи и за парот account_id и account_email, но тие се достапни преку FD1 од user_id, па не мора да бидат во клучот. 168 176 169 177 === 3.4 Пресметка на затворач === 170 178 171 '''Чекор 1:''' Започнуваме со {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids} и пресметуваме затворач:172 173 {{{ 174 {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids}⁺:175 - Од FD2 (verification_token_uuid →): добиваме token_created_at, token_expire d_at, user_id179 '''Чекор 1:''' Започнуваме со {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids} и пресметуваме затворач: 180 181 {{{ 182 {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids}⁺: 183 - Од FD2 (verification_token_uuid →): добиваме token_created_at, token_expires_at, user_id 176 184 - Од FD3 (meeting_reminder_id →): добиваме meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, user_id 177 - Од FD1 (user_id →): добиваме user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points 185 - Од FD1 (user_id →): добиваме user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, account_id 186 - Од FD4 (expert_id →): добиваме account_id 187 - Од FD19 (account_id →): добиваме account_email, account_password_hash, account_name 178 188 - Од FD18 (user_email →): добиваме user_id 179 }}} 180 181 '''{verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids}⁺ ≠ Universal_Relation_Shifter''' 189 - Од FD30 (account_email →): добиваме account_id 190 }}} 191 192 '''{verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids}⁺ ≠ Universal_Relation_Shifter''' 182 193 183 194 '''Недостасуваат:''' 184 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash,195 language_id, language_value, 185 196 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 186 course_version_id, version_number, version_creat ion_date, version_active,197 course_version_id, version_number, version_created_at, version_is_active, 187 198 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 188 199 payment_id, payment_amount, payment_date, payment_method, payment_status, 189 200 review_id, review_rating, review_comment, review_date, 190 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,191 course_content_id, content_position, 192 course_content_translate_id, content_translate_title, content_translate_language,193 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 194 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,195 user_course_progress_id, progress_ completed, progress_completed_at,201 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 202 course_content_id, content_position, 203 course_content_translate_id, content_translate_title, 204 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 205 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 206 user_course_progress_id, progress_is_completed, progress_completed_at, 196 207 tag_id, tag_type, 197 tag_translate_id, tag_ translate_language, tag_value208 tag_translate_id, tag_value 198 209 199 210 '''Чекор 2:''' Додаваме user_course_progress_id: 200 211 201 212 {{{ 202 {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id}⁺:213 {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id}⁺: 203 214 - Сè од претходно, плус: 204 - Од FD 6 (user_course_progress_id →): добиваме progress_completed, progress_completed_at, enrollment_id, course_lecture_id215 - Од FD17 (user_course_progress_id →): добиваме progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id 205 216 - Од FD15 (course_lecture_id →): добиваме lecture_duration_minutes, lecture_position, lecture_content_type, course_content_id 206 217 - Од FD13 (course_content_id →): добиваме content_position, course_version_id … … 208 219 - Од FD7 (payment_id →): добиваме payment_amount, payment_date, payment_method, payment_status, enrollment_id 209 220 - Од FD8 (review_id →): добиваме review_rating, review_comment, review_date, enrollment_id 210 - Од FD11 (course_version_id →): добиваме version_number, version_creat ion_date, version_active, course_id221 - Од FD11 (course_version_id →): добиваме version_number, version_created_at, version_is_active, course_id 211 222 - Од FD5 (course_id →): добиваме course_image_url, course_color, course_difficulty, course_duration_minutes, course_price 212 223 }}} 213 224 214 '''{verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id}⁺ ≠ Universal_Relation_Shifter'''225 '''{verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id}⁺ ≠ Universal_Relation_Shifter''' 215 226 216 227 '''Недостасуваат:''' 217 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash,218 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,219 course_content_translate_id, content_translate_title, content_translate_language,220 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,228 language_id, language_value, 229 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 230 course_content_translate_id, content_translate_title, 231 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 221 232 tag_id, tag_type, 222 tag_translate_id, tag_ translate_language, tag_value223 224 '''Чекор 3:''' Додаваме expert_id,course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id:225 226 {{{ 227 {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺:233 tag_translate_id, tag_value 234 235 '''Чекор 3:''' Додаваме course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id: 236 237 {{{ 238 {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺: 228 239 - Сè од претходно, плус: 229 - Од FD 4 (expert_id →): добиваме expert_name, expert_email, expert_login_provider, expert_password_hash230 - Од FD1 6 (course_lecture_translate_id →): добиваме lecture_title, lecture_language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id231 - Од FD1 4 (course_content_translate_id →): добиваме content_translate_title, content_translate_language, course_content_id232 - Од FD1 2 (course_translate_id →): добиваме course_translate_language, course_title_short, course_title, course_description_short, course_description233 - Од FD 10 (tag_translate_id →): добиваме tag_translate_language, tag_value, tag_id240 - Од FD16 (course_lecture_translate_id →): добиваме lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id 241 - Од FD14 (course_content_translate_id →): добиваме content_translate_title, course_content_id, language_id 242 - Од FD12 (course_translate_id →): добиваме course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id 243 - Од FD10 (tag_translate_id →): добиваме tag_value, tag_id, language_id 244 - Од FD31 (language_id →): добиваме language_value 234 245 - Од FD9 (tag_id →): добиваме tag_type 235 246 - Од FD28 ({course_translate_id, course_what_will_be_learned} →): добиваме ∅ 236 247 }}} 237 248 238 '''{verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺ = Universal_Relation_Shifter''' (ги содржи сите атрибути) ✓249 '''{verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺ = Universal_Relation_Shifter''' (ги содржи сите атрибути) ✓ 239 250 240 251 === 3.5 Проверка за минималност === 241 252 242 253 ||= Подмножество =||= Затворач =||= = Universal_Relation_Shifter? =|| 243 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids}⁺ || Недостасуваат атрибути одuser_course_progress || ✗ НЕ ||244 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress}⁺ || Недостасуваат атрибути од expert|| ✗ НЕ ||245 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id}⁺ || Недостасуваат атрибути од course_translate || ✗ НЕ ||246 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_translate_id}⁺ || Недостасуваат атрибути од course_lecture_translate || ✗ НЕ ||247 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_translate_id, course_lecture_translate_id}⁺ || Недостасуваат атрибути од course_content_translate || ✗ НЕ ||248 || {verification_token_uuid, meeting_ reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_translate_id, course_lecture_translate_id, course_content_translate_id}⁺ || Недостасуваат атрибути од tag_translate || ✗ НЕ||249 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, enrollment_id, course_lecture_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} || Сите атрибути се присути || ✓ ДА ||250 || {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_translate_id, course_lecture_translate_id, course_content_translate_id, tag_translate_id}⁺ || Сите атрибути се присути || ✓ ДА ||251 252 '''Заклучок:''' {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} е минимален и е кандидат клуч.254 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids}⁺ || Недостасуваат атрибути од user_course_progress || ✗ НЕ || 255 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id}⁺ || Недостасуваат атрибути од course_translate || ✗ НЕ || 256 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_translate_id}⁺ || Недостасуваат атрибути од course_lecture_translate || ✗ НЕ || 257 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_translate_id, course_lecture_translate_id}⁺ || Недостасуваат атрибути од course_content_translate || ✗ НЕ || 258 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_translate_id, course_lecture_translate_id, course_content_translate_id}⁺ || Недостасуваат атрибути од tag_translate || ✗ НЕ || 259 || {verification_token_uuid, meeting_link, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺ || Сите атрибути се присутни || ✓ ДА || 260 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, enrollment_id, course_lecture_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} || Сите атрибути се присутни || ✓ ДА || 261 || {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}⁺ || Сите атрибути се присутни || ✓ ДА || 262 263 '''Заклучок:''' {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} е минимален и е кандидат клуч. 253 264 254 265 === 3.6 Други кандидат клучеви === 255 266 256 Дополнителен кандидате клуч кој го разгледував беше '''{verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, enrollment_id, course_lecture_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}''', каде наместо user_course_progress_id присутни се enrollment_id и course_lecture_id. Меѓутоа овој кандидат клуч е поголем од тој со user_course_progress_id, па затоа не го земам во предвид при бирање на примарен клуч. 267 Дополнителен кандидат клуч кој го разгледував беше '''{verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, enrollment_id, course_lecture_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}''', каде наместо user_course_progress_id присутни се enrollment_id и course_lecture_id. Меѓутоа овој кандидат клуч е поголем од тој со user_course_progress_id, па затоа не го земам во предвид при бирање на примарен клуч. 268 269 Втор кандидат клуч со иста големина се добива ако наместо meeting_reminder_id се земе meeting_link (FD33). Го избирам meeting_reminder_id бидејќи е сурогат клуч со фиксна должина, наспроти meeting_link кој е текстуален атрибут. 257 270 258 271 === 3.7 Избор на примарен клуч === 259 272 260 '''Избран примарен клуч: {verification_token_uuid, meeting_reminder_id, course_what_will_be_learned, user_course_favorite_ids, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}'''273 '''Избран примарен клуч: {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}''' 261 274 262 275 '''Образложение:''' … … 277 290 278 291 {{{ 279 Course_ What_Will_Be_Learned(course_translate_id, course_what_will_be_learned)292 Course_Translate_What_Will_Be_Learned(course_translate_id, course_what_will_be_learned) 280 293 PK: {course_translate_id, course_what_will_be_learned} 281 294 … … 283 296 284 297 Universal_Relation_Shifter_Base_1( 285 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, user_course_favorite_ids, 298 account_id, account_email, account_password_hash, account_name, 299 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, user_favorite_course_ids, 286 300 meeting_reminder_id, meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, 287 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash, 301 expert_id, 302 language_id, language_value, 288 303 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 289 course_version_id, version_number, version_creat ion_date, version_active,304 course_version_id, version_number, version_created_at, version_is_active, 290 305 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 291 306 payment_id, payment_amount, payment_date, payment_method, payment_status, 292 307 review_id, review_rating, review_comment, review_date, 293 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,294 course_content_id, content_position, 295 course_content_translate_id, content_translate_title, content_translate_language,296 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 297 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,298 user_course_progress_id, progress_ completed, progress_completed_at,299 verification_token_uuid, token_created_at, token_expire d_at,308 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 309 course_content_id, content_position, 310 course_content_translate_id, content_translate_title, 311 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 312 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 313 user_course_progress_id, progress_is_completed, progress_completed_at, 314 verification_token_uuid, token_created_at, token_expires_at, 300 315 tag_id, tag_type, 301 tag_translate_id, tag_ translate_language, tag_value302 ) 303 PK: {verification_token_uuid, meeting_reminder_id, user_course_favorite_ids, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}316 tag_translate_id, tag_value 317 ) 318 PK: {verification_token_uuid, meeting_reminder_id, expert_id, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} 304 319 }}} 305 320 306 321 '''Проверка за lossless join:''' Може да се реконструира преку course_translate_id 307 322 308 '''Проверка за dependency preservation:''' FD28 е зачувана во Course_ What_Will_Be_Learned323 '''Проверка за dependency preservation:''' FD28 е зачувана во Course_Translate_What_Will_Be_Learned 309 324 310 325 === Чекор 4.2: Декомпозиција на релацијата Universal_Relation_Shifter === 311 326 312 '''Нарушува 1NF: '''Релацијата не е во 1NF бидејќи атрибутот user_ course_favorite_ids претставува повеќевредносен (multi-valued) атрибут. Секој user може да има повеќе ставки од user_course_favorite_ids.327 '''Нарушува 1NF: '''Релацијата не е во 1NF бидејќи атрибутот user_favorite_course_ids претставува повеќевредносен (multi-valued) атрибут. Секој user може да има повеќе ставки од user_favorite_course_ids. 313 328 314 329 '''Декомпозиција:''' 315 330 316 331 {{{ 317 User_ Course_Favorite_Id(user_id, user_course_favorite_id)318 PK: {user_id, user_course_favorite_id}319 320 Universal_Relation_Shifter_Base = Universal_Relation_Shifter_Base_1 - {user_ course_favorite_ids}332 User_Favorite_Course(user_id, course_id) 333 PK: {user_id, course_id} 334 335 Universal_Relation_Shifter_Base = Universal_Relation_Shifter_Base_1 - {user_favorite_course_ids} 321 336 322 337 Universal_Relation_Shifter_Base( 323 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 338 account_id, account_email, account_password_hash, account_name, 339 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 324 340 meeting_reminder_id, meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, 325 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash, 341 expert_id, 342 language_id, language_value, 326 343 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 327 course_version_id, version_number, version_creat ion_date, version_active,344 course_version_id, version_number, version_created_at, version_is_active, 328 345 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 329 346 payment_id, payment_amount, payment_date, payment_method, payment_status, 330 347 review_id, review_rating, review_comment, review_date, 331 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,332 course_content_id, content_position, 333 course_content_translate_id, content_translate_title, content_translate_language,334 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 335 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,336 user_course_progress_id, progress_ completed, progress_completed_at,337 verification_token_uuid, token_created_at, token_expire d_at,348 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 349 course_content_id, content_position, 350 course_content_translate_id, content_translate_title, 351 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 352 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 353 user_course_progress_id, progress_is_completed, progress_completed_at, 354 verification_token_uuid, token_created_at, token_expires_at, 338 355 tag_id, tag_type, 339 tag_translate_id, tag_ translate_language, tag_value340 ) 341 PK: {verification_token_uuid, meeting_reminder_id, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}356 tag_translate_id, tag_value 357 ) 358 PK: {verification_token_uuid, meeting_reminder_id, expert_id, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} 342 359 }}} 343 360 344 361 '''Проверка за lossless join:''' Може да се реконструира преку user_id 345 362 346 '''Проверка за dependency preservation:''' FD29 е зачувана во User_ Course_Favorite_Id363 '''Проверка за dependency preservation:''' FD29 е зачувана во User_Favorite_Course 347 364 348 365 … … 351 368 За да биде во 2NF, секој не-клучен атрибут мора целосно да зависи од примарниот клуч (нема парцијални зависности). 352 369 353 Примарен клуч во Universal_Relation_Shifter_Base: '''{verification_token_uuid, meeting_reminder_id, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}'''370 Примарен клуч во Universal_Relation_Shifter_Base: '''{verification_token_uuid, meeting_reminder_id, expert_id, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}''' 354 371 355 372 '''Парцијални зависности (атрибути кои зависат од дел од клучот):''' 356 373 ||= FD =||= Детерминант =||= Дел од клуч? =||= Парцијална зависност? =|| 357 || FD1: user_id → user_* || user_id || НЕ (транзитивно преку user_course_progress_id) || Не директно ||358 || FD2: verification_token_uuid → token_created_at, token_expire d_at, user_id || verification_token_uuid || ДА (дел од примарен клуч) || '''ДА''' ||374 || FD1: user_id → user_*, account_id || user_id || НЕ (транзитивно преку user_course_progress_id) || Не директно || 375 || FD2: verification_token_uuid → token_created_at, token_expires_at, user_id || verification_token_uuid || ДА (дел од примарен клуч) || '''ДА''' || 359 376 || FD3: meeting_reminder_id → meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, user_id || meeting_reminder_id || ДА (дел од примарен клуч) || '''ДА''' || 360 || FD4: expert_id → expert_name, expert_email, expert_login_provider, expert_password_hash|| expert_id || ДА (дел од примарен клуч) || '''ДА''' ||377 || FD4: expert_id → account_id || expert_id || ДА (дел од примарен клуч) || '''ДА''' || 361 378 || FD5: course_id → course_image_url, course_color, course_difficulty, course_duration_minutes, course_price || course_id || НЕ (транзитивно преку user_course_progress_id) || Не директно || 362 379 || FD6: enrollment_id → enrollment_*, user_id, course_version_id, payment_id, review_id || enrollment_id || НЕ (транзитивно преку user_course_progress_id) || Не директно || … … 364 381 || FD8: review_id → review_rating, review_comment, review_date, enrollment_id || review_id || НЕ (транзитивно преку user_course_progress_id) || Не директно || 365 382 || FD9: tag_id → tag_type || tag_id || НЕ (транзитивно преку tag_translate_id) || Не директно || 366 || FD10: tag_translate_id → tag_ translate_language, tag_value, tag_id || tag_translate_id || ДА (дел од примарен клуч) || '''ДА''' ||367 || FD11: course_version_id → version_number, version_creat ion_date, version_active, course_id || course_version_id || НЕ (транзитивно преку user_course_progress_id) || Не директно ||368 || FD12: course_translate_id → course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id || course_translate_id || ДА (дел од примарен клуч) || '''ДА''' ||383 || FD10: tag_translate_id → tag_value, tag_id, language_id || tag_translate_id || ДА (дел од примарен клуч) || '''ДА''' || 384 || FD11: course_version_id → version_number, version_created_at, version_is_active, course_id || course_version_id || НЕ (транзитивно преку user_course_progress_id) || Не директно || 385 || FD12: course_translate_id → course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id || course_translate_id || ДА (дел од примарен клуч) || '''ДА''' || 369 386 || FD13: course_content_id → content_position, course_version_id || course_content_id || НЕ (транзитивно преку course_content_translate_id) || Не директно || 370 || FD14: course_content_translate_id → content_translate_title, co ntent_translate_language, course_content_id || course_content_translate_id || ДА (дел од примарен клуч) || '''ДА''' ||387 || FD14: course_content_translate_id → content_translate_title, course_content_id, language_id || course_content_translate_id || ДА (дел од примарен клуч) || '''ДА''' || 371 388 || FD15: course_lecture_id → lecture_duration_minutes, lecture_position, lecture_content_type, course_content_id || course_lecture_id || НЕ (транзитивно преку course_lecture_translate_id) || Не директно || 372 || FD16: course_lecture_translate_id → lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id || course_lecture_translate_id || ДА (дел од примарен клуч) || '''ДА''' ||373 || FD17: user_course_progress_id → progress_ completed, progress_completed_at, enrollment_id, course_lecture_id || user_course_progress_id || ДА (дел од примарен клуч) || '''ДА''' ||389 || FD16: course_lecture_translate_id → lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id || course_lecture_translate_id || ДА (дел од примарен клуч) || '''ДА''' || 390 || FD17: user_course_progress_id → progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id || user_course_progress_id || ДА (дел од примарен клуч) || '''ДА''' || 374 391 || FD18: user_email → user_id || user_email || НЕ || Не || 375 || FD19: expert_email → expert_id || expert_email || НЕ || Не||392 || FD19: account_id → account_email, account_password_hash, account_name || account_id || НЕ (транзитивно преку expert_id и user_id) || Не директно || 376 393 || FD20: (course_id, version_number) → course_version_id || course_id, version_number || НЕ || Не || 377 || FD21: (course_id, course_translate_language) → course_translate_id || course_id, course_translate_language|| НЕ || Не ||378 || FD22: (course_lecture_id, l ecture_language) → course_lecture_translate_id || course_lecture_id, lecture_language|| НЕ || Не ||379 || FD23: (course_content_id, content_translate_language) → course_content_translate_id || course_content_id, content_translate_language|| НЕ || Не ||380 || FD24: (tag_id, tag_translate_language) → tag_translate_id || tag_id, tag_translate_language|| НЕ || Не ||394 || FD21: (course_id, language_id) → course_translate_id || course_id, language_id || НЕ || Не || 395 || FD22: (course_lecture_id, language_id) → course_lecture_translate_id || course_lecture_id, language_id || НЕ || Не || 396 || FD23: (course_content_id, language_id) → course_content_translate_id || course_content_id, language_id || НЕ || Не || 397 || FD24: (tag_id, language_id) → tag_translate_id || tag_id, language_id || НЕ || Не || 381 398 || FD25: (enrollment_id, course_lecture_id) → user_course_progress_id || enrollment_id, course_lecture_id || НЕ || Не || 382 399 || FD26: (course_version_id, content_position) → course_content_id || course_version_id, content_position || НЕ || Не || 383 400 || FD27: (course_content_id, lecture_position) → course_lecture_id || course_content_id, lecture_position || НЕ || Не || 401 || FD30: account_email → account_id || account_email || НЕ || Не || 402 || FD31: language_id → language_value || language_id || НЕ (транзитивно преку course_translate_id) || Не директно || 403 || FD32: language_value → language_id || language_value || НЕ || Не || 404 || FD33: meeting_link → meeting_reminder_id || meeting_link || НЕ || Не || 384 405 385 406 '''Заклучок:''' Релацијата не е во 2NF бидејќи има парцијални зависности. Атрибутите на '''FD2, FD3, FD4, FD10, FD12, FD14, FD16, FD17''' зависат само од дел од примарниот клуч, а не од целиот клуч. … … 387 408 '''Идентификувани парцијални зависности што ја нарушуваат 2NF:''' 388 409 389 1. '''FD2:''' verification_token_uuid → token_created_at, token_expire d_at, user_id410 1. '''FD2:''' verification_token_uuid → token_created_at, token_expires_at, user_id 390 411 2. '''FD3:''' meeting_reminder_id → meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, user_id 391 3. '''FD4:''' expert_id → expert_name, expert_email, expert_login_provider, expert_password_hash392 4. '''FD10:''' tag_translate_id → tag_ translate_language, tag_value, tag_id393 5. '''FD12:''' course_translate_id → course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id394 6. '''FD14:''' course_content_translate_id → content_translate_title, co ntent_translate_language, course_content_id395 7. '''FD16:''' course_lecture_translate_id → lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id396 8. '''FD17:''' user_course_progress_id → progress_ completed, progress_completed_at, enrollment_id, course_lecture_id412 3. '''FD4:''' expert_id → account_id 413 4. '''FD10:''' tag_translate_id → tag_value, tag_id, language_id 414 5. '''FD12:''' course_translate_id → course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id 415 6. '''FD14:''' course_content_translate_id → content_translate_title, course_content_id, language_id 416 7. '''FD16:''' course_lecture_translate_id → lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id 417 8. '''FD17:''' user_course_progress_id → progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id 397 418 398 419 … … 401 422 == 5. 2NF Декомпозиција == 402 423 424 '''Забелешка за надворешните клучеви:''' При секоја декомпозиција, атрибутот кој служи како надворешен клуч (account_id, language_id, course_id, course_content_id, ...) се пренесува во новата релација, но останува и во базната релација сè додека не се извлече неговиот сопствен ентитет. 425 403 426 === Чекор 5.1: Декомпозиција по FD2 (verification_token_uuid → ...) === 404 427 405 '''Нарушува 2NF:''' verification_token_uuid е дел од примарниот клуч, а token_created_at, token_expire d_at зависат само од verification_token_uuid.428 '''Нарушува 2NF:''' verification_token_uuid е дел од примарниот клуч, а token_created_at, token_expires_at зависат само од verification_token_uuid. 406 429 407 430 '''Декомпозиција:''' 408 431 409 432 {{{ 410 Verification_Token(verification_token_uuid, token_created_at, token_expire d_at, user_id)433 Verification_Token(verification_token_uuid, token_created_at, token_expires_at, user_id) 411 434 PK: verification_token_uuid 412 435 413 Universal_Relation_Shifter_Base_1 = Universal_Relation_Shifter_Base - {verification_token_uuid, token_created_at, token_expire d_at}436 Universal_Relation_Shifter_Base_1 = Universal_Relation_Shifter_Base - {verification_token_uuid, token_created_at, token_expires_at} 414 437 415 438 Universal_Relation_Shifter_Base_1( 416 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 439 account_id, account_email, account_password_hash, account_name, 440 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 417 441 meeting_reminder_id, meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, 418 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash, 442 expert_id, 443 language_id, language_value, 419 444 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 420 course_version_id, version_number, version_creat ion_date, version_active,445 course_version_id, version_number, version_created_at, version_is_active, 421 446 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 422 447 payment_id, payment_amount, payment_date, payment_method, payment_status, 423 448 review_id, review_rating, review_comment, review_date, 424 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,425 course_content_id, content_position, 426 course_content_translate_id, content_translate_title, content_translate_language,427 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 428 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,429 user_course_progress_id, progress_ completed, progress_completed_at,449 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 450 course_content_id, content_position, 451 course_content_translate_id, content_translate_title, 452 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 453 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 454 user_course_progress_id, progress_is_completed, progress_completed_at, 430 455 tag_id, tag_type, 431 tag_translate_id, tag_ translate_language, tag_value432 ) 433 PK: {meeting_reminder_id, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}456 tag_translate_id, tag_value 457 ) 458 PK: {meeting_reminder_id, expert_id, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} 434 459 }}} 435 460 … … 451 476 452 477 Universal_Relation_Shifter_Base_2( 453 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 454 expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash, 478 account_id, account_email, account_password_hash, account_name, 479 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 480 expert_id, 481 language_id, language_value, 455 482 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 456 course_version_id, version_number, version_creat ion_date, version_active,483 course_version_id, version_number, version_created_at, version_is_active, 457 484 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 458 485 payment_id, payment_amount, payment_date, payment_method, payment_status, 459 486 review_id, review_rating, review_comment, review_date, 460 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,461 course_content_id, content_position, 462 course_content_translate_id, content_translate_title, content_translate_language,463 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 464 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,465 user_course_progress_id, progress_ completed, progress_completed_at,487 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 488 course_content_id, content_position, 489 course_content_translate_id, content_translate_title, 490 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 491 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 492 user_course_progress_id, progress_is_completed, progress_completed_at, 466 493 tag_id, tag_type, 467 tag_translate_id, tag_ translate_language, tag_value468 ) 469 PK: { user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}494 tag_translate_id, tag_value 495 ) 496 PK: {expert_id, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} 470 497 }}} 471 498 472 499 '''Проверка за lossless join:''' Може да се реконструира преку user_id 473 474 '''Проверка за dependency preservation:''' FD3 е зачуванаво Meeting_Reminder500 501 '''Проверка за dependency preservation:''' FD3 и FD33 се зачувани во Meeting_Reminder 475 502 476 503 === Чекор 5.3: Декомпозиција по FD4 (expert_id → ...) === 477 504 478 '''Нарушува 2NF:''' expert_id е дел од примарниот клуч, а expert_name, expert_email, expert_login_provider, expert_password_hash зависатсамо од expert_id.505 '''Нарушува 2NF:''' expert_id е дел од примарниот клуч, а account_id зависи само од expert_id. 479 506 480 507 '''Декомпозиција:''' 481 508 482 509 {{{ 483 Expert(expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash)510 Expert(expert_id, account_id) 484 511 PK: expert_id 485 512 486 Universal_Relation_Shifter_Base_3 = Universal_Relation_Shifter_Base_2 - {expert_id , expert_name, expert_email, expert_login_provider, expert_password_hash}513 Universal_Relation_Shifter_Base_3 = Universal_Relation_Shifter_Base_2 - {expert_id} 487 514 488 515 Universal_Relation_Shifter_Base_3( 489 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 490 expert_id, 516 account_id, account_email, account_password_hash, account_name, 517 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 518 language_id, language_value, 491 519 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 492 course_version_id, version_number, version_creat ion_date, version_active,520 course_version_id, version_number, version_created_at, version_is_active, 493 521 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 494 522 payment_id, payment_amount, payment_date, payment_method, payment_status, 495 523 review_id, review_rating, review_comment, review_date, 496 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,497 course_content_id, content_position, 498 course_content_translate_id, content_translate_title, content_translate_language,499 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 500 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,501 user_course_progress_id, progress_ completed, progress_completed_at,524 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 525 course_content_id, content_position, 526 course_content_translate_id, content_translate_title, 527 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 528 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 529 user_course_progress_id, progress_is_completed, progress_completed_at, 502 530 tag_id, tag_type, 503 tag_translate_id, tag_ translate_language, tag_value531 tag_translate_id, tag_value 504 532 ) 505 533 PK: {user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id} 506 534 }}} 507 535 508 '''Проверка за lossless join:''' Може да се реконструира преку expert_id509 536 '''Проверка за lossless join:''' Може да се реконструира преку account_id 537 510 538 '''Проверка за dependency preservation:''' FD4 е зачувана во Expert 511 539 512 540 === Чекор 5.4: Декомпозиција по FD10 (tag_translate_id → ...) === 513 541 514 '''Нарушува 2NF:''' tag_translate_id е дел од примарниот клуч, а tag_ translate_language, tag_value зависатсамо од tag_translate_id.542 '''Нарушува 2NF:''' tag_translate_id е дел од примарниот клуч, а tag_value зависи само од tag_translate_id. 515 543 516 544 '''Декомпозиција:''' 517 545 518 546 {{{ 519 Tag_Translate(tag_translate_id, tag_ translate_language, tag_value, tag_id)547 Tag_Translate(tag_translate_id, tag_value, tag_id, language_id) 520 548 PK: tag_translate_id 521 549 522 Universal_Relation_Shifter_Base_4 = Universal_Relation_Shifter_Base_3 - {tag_translate_id, tag_ translate_language, tag_value}550 Universal_Relation_Shifter_Base_4 = Universal_Relation_Shifter_Base_3 - {tag_translate_id, tag_value} 523 551 524 552 Universal_Relation_Shifter_Base_4( 525 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 526 expert_id, 553 account_id, account_email, account_password_hash, account_name, 554 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 555 language_id, language_value, 527 556 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 528 course_version_id, version_number, version_creat ion_date, version_active,557 course_version_id, version_number, version_created_at, version_is_active, 529 558 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 530 559 payment_id, payment_amount, payment_date, payment_method, payment_status, 531 560 review_id, review_rating, review_comment, review_date, 532 course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long,533 course_content_id, content_position, 534 course_content_translate_id, content_translate_title, content_translate_language,535 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 536 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,537 user_course_progress_id, progress_ completed, progress_completed_at,561 course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, 562 course_content_id, content_position, 563 course_content_translate_id, content_translate_title, 564 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 565 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 566 user_course_progress_id, progress_is_completed, progress_completed_at, 538 567 tag_id, tag_type 539 568 ) … … 542 571 543 572 '''Проверка за lossless join:''' Може да се реконструира преку tag_id 544 573 545 574 '''Проверка за dependency preservation:''' FD10 е зачувана во Tag_Translate 546 575 547 576 === Чекор 5.5: Декомпозиција по FD12 (course_translate_id → ...) === 548 577 549 '''Нарушува 2NF:''' course_translate_id е дел од примарниот клуч, а course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long зависат само од course_translate_id.578 '''Нарушува 2NF:''' course_translate_id е дел од примарниот клуч, а course_title_short, course_title, course_description_short, course_description, course_description_long зависат само од course_translate_id. 550 579 551 580 '''Декомпозиција:''' 552 581 553 582 {{{ 554 Course_Translate(course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id)583 Course_Translate(course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id) 555 584 PK: course_translate_id 556 585 557 Universal_Relation_Shifter_Base_5 = Universal_Relation_Shifter_Base_4 - {course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long}586 Universal_Relation_Shifter_Base_5 = Universal_Relation_Shifter_Base_4 - {course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long} 558 587 559 588 Universal_Relation_Shifter_Base_5( 560 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 561 expert_id, 589 account_id, account_email, account_password_hash, account_name, 590 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 591 language_id, language_value, 562 592 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 563 course_version_id, version_number, version_creat ion_date, version_active,593 course_version_id, version_number, version_created_at, version_is_active, 564 594 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 565 595 payment_id, payment_amount, payment_date, payment_method, payment_status, 566 596 review_id, review_rating, review_comment, review_date, 567 597 course_content_id, content_position, 568 course_content_translate_id, content_translate_title, content_translate_language,569 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 570 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,571 user_course_progress_id, progress_ completed, progress_completed_at,598 course_content_translate_id, content_translate_title, 599 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 600 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 601 user_course_progress_id, progress_is_completed, progress_completed_at, 572 602 tag_id, tag_type 573 603 ) … … 576 606 577 607 '''Проверка за lossless join:''' Може да се реконструира преку course_id 578 608 579 609 '''Проверка за dependency preservation:''' FD12 е зачувана во Course_Translate 580 610 581 611 === Чекор 5.6: Декомпозиција по FD14 (course_content_translate_id → ...) === 582 612 583 '''Нарушува 2NF:''' course_content_translate_id е дел од примарниот клуч, а content_translate_title , content_translate_language зависатсамо од course_content_translate_id.613 '''Нарушува 2NF:''' course_content_translate_id е дел од примарниот клуч, а content_translate_title зависи само од course_content_translate_id. 584 614 585 615 '''Декомпозиција:''' 586 616 587 617 {{{ 588 Course_Content_Translate(course_content_translate_id, content_translate_title, co ntent_translate_language, course_content_id)618 Course_Content_Translate(course_content_translate_id, content_translate_title, course_content_id, language_id) 589 619 PK: course_content_translate_id 590 620 591 Universal_Relation_Shifter_Base_6 = Universal_Relation_Shifter_Base_5 - {course_content_translate_id, content_translate_title , content_translate_language}621 Universal_Relation_Shifter_Base_6 = Universal_Relation_Shifter_Base_5 - {course_content_translate_id, content_translate_title} 592 622 593 623 Universal_Relation_Shifter_Base_6( 594 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 595 expert_id, 624 account_id, account_email, account_password_hash, account_name, 625 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 626 language_id, language_value, 596 627 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 597 course_version_id, version_number, version_creat ion_date, version_active,628 course_version_id, version_number, version_created_at, version_is_active, 598 629 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 599 630 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 601 632 course_content_id, content_position, 602 633 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 603 course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text,604 user_course_progress_id, progress_ completed, progress_completed_at,634 course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, 635 user_course_progress_id, progress_is_completed, progress_completed_at, 605 636 tag_id, tag_type 606 637 ) … … 609 640 610 641 '''Проверка за lossless join:''' Може да се реконструира преку course_content_id 611 642 612 643 '''Проверка за dependency preservation:''' FD14 е зачувана во Course_Content_Translate 613 644 614 645 === Чекор 5.7: Декомпозиција по FD16 (course_lecture_translate_id → ...) === 615 646 616 '''Нарушува 2NF:''' course_lecture_translate_id е дел од примарниот клуч, а lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text зависат само од course_lecture_translate_id.647 '''Нарушува 2NF:''' course_lecture_translate_id е дел од примарниот клуч, а lecture_title, lecture_content_file_name, lecture_description, lecture_content_text зависат само од course_lecture_translate_id. 617 648 618 649 '''Декомпозиција:''' 619 650 620 651 {{{ 621 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id)652 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id) 622 653 PK: course_lecture_translate_id 623 654 624 Universal_Relation_Shifter_Base_7 = Universal_Relation_Shifter_Base_6 - {course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text}655 Universal_Relation_Shifter_Base_7 = Universal_Relation_Shifter_Base_6 - {course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text} 625 656 626 657 Universal_Relation_Shifter_Base_7( 627 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 628 expert_id, 658 account_id, account_email, account_password_hash, account_name, 659 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 660 language_id, language_value, 629 661 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 630 course_version_id, version_number, version_creat ion_date, version_active,662 course_version_id, version_number, version_created_at, version_is_active, 631 663 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 632 664 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 634 666 course_content_id, content_position, 635 667 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, 636 user_course_progress_id, progress_ completed, progress_completed_at,668 user_course_progress_id, progress_is_completed, progress_completed_at, 637 669 tag_id, tag_type 638 670 ) … … 641 673 642 674 '''Проверка за lossless join:''' Може да се реконструира преку course_lecture_id 643 675 644 676 '''Проверка за dependency preservation:''' FD16 е зачувана во Course_Lecture_Translate 645 677 646 678 === Чекор 5.8: Декомпозиција по FD17 (user_course_progress_id → ...) === 647 679 648 '''Нарушува 2NF:''' user_course_progress_id е дел од примарниот клуч, а progress_ completed, progress_completed_at зависат само од user_course_progress_id.680 '''Нарушува 2NF:''' user_course_progress_id е дел од примарниот клуч, а progress_is_completed, progress_completed_at зависат само од user_course_progress_id. 649 681 650 682 '''Декомпозиција:''' 651 683 652 684 {{{ 653 User_Course_Progress(user_course_progress_id, progress_ completed, progress_completed_at, enrollment_id, course_lecture_id)685 User_Course_Progress(user_course_progress_id, progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id) 654 686 PK: user_course_progress_id 655 687 656 Universal_Relation_Shifter_Base_8 = Universal_Relation_Shifter_Base_7 - {user_course_progress_id, progress_ completed, progress_completed_at}688 Universal_Relation_Shifter_Base_8 = Universal_Relation_Shifter_Base_7 - {user_course_progress_id, progress_is_completed, progress_completed_at} 657 689 658 690 Universal_Relation_Shifter_Base_8( 659 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 660 expert_id, 691 account_id, account_email, account_password_hash, account_name, 692 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 693 language_id, language_value, 661 694 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 662 course_version_id, version_number, version_creat ion_date, version_active,695 course_version_id, version_number, version_created_at, version_is_active, 663 696 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 664 697 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 672 705 673 706 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id и course_lecture_id 674 707 675 708 '''Проверка за dependency preservation:''' FD17 е зачувана во User_Course_Progress 676 709 … … 678 711 679 712 {{{ 680 User_ Course_Favorite_Id(user_id, user_course_favorite_id)681 PK: {user_id, user_course_favorite_id}682 683 Course_ What_Will_Be_Learned(course_translate_id, course_what_will_be_learned)713 User_Favorite_Course(user_id, course_id) 714 PK: {user_id, course_id} 715 716 Course_Translate_What_Will_Be_Learned(course_translate_id, course_what_will_be_learned) 684 717 PK: {course_translate_id, course_what_will_be_learned} 685 718 686 Verification_Token(verification_token_uuid, token_created_at, token_expire d_at, user_id)719 Verification_Token(verification_token_uuid, token_created_at, token_expires_at, user_id) 687 720 PK: verification_token_uuid 688 721 … … 690 723 PK: meeting_reminder_id 691 724 692 Expert(expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash)725 Expert(expert_id, account_id) 693 726 PK: expert_id 694 727 695 Tag_Translate(tag_translate_id, tag_ translate_language, tag_value, tag_id)728 Tag_Translate(tag_translate_id, tag_value, tag_id, language_id) 696 729 PK: tag_translate_id 697 730 698 Course_Translate(course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id)731 Course_Translate(course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id) 699 732 PK: course_translate_id 700 733 701 Course_Content_Translate(course_content_translate_id, content_translate_title, co ntent_translate_language, course_content_id)734 Course_Content_Translate(course_content_translate_id, content_translate_title, course_content_id, language_id) 702 735 PK: course_content_translate_id 703 736 704 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id)737 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id) 705 738 PK: course_lecture_translate_id 706 739 707 User_Course_Progress(user_course_progress_id, progress_ completed, progress_completed_at, enrollment_id, course_lecture_id)740 User_Course_Progress(user_course_progress_id, progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id) 708 741 PK: user_course_progress_id 709 742 710 743 Universal_Relation_Shifter_Base_8( 711 user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points, 712 expert_id, 744 account_id, account_email, account_password_hash, account_name, 745 user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, 746 language_id, language_value, 713 747 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 714 course_version_id, version_number, version_creat ion_date, version_active,748 course_version_id, version_number, version_created_at, version_is_active, 715 749 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 716 750 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 729 763 === Проверка за транзитивни зависности во секоја релација === 730 764 731 ==== Verification_Token(verification_token_uuid, token_created_at, token_expire d_at, user_id) ====765 ==== Verification_Token(verification_token_uuid, token_created_at, token_expires_at, user_id) ==== 732 766 733 767 '''Транзитивни зависности:''' … … 740 774 741 775 '''Транзитивни зависности:''' 742 * meeting_reminder_id → user Id → user_*?776 * meeting_reminder_id → user_id → user_*? 743 777 * user_* атрибутите НЕ се во Meeting_Reminder. 778 * meeting_link → meeting_reminder_id (FD33) е зависност кон клучот, не транзитивна зависност. 744 779 745 780 '''Заклучок:''' Meeting_Reminder е во 3NF ✓ 746 781 747 ==== Expert(expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash) ====782 ==== Expert(expert_id, account_id) ==== 748 783 749 784 '''Транзитивни зависности:''' 750 * Нема не-клучни атрибути кои одредуваат други не-клучни атрибути. 785 * expert_id → account_id → account_*? 786 * account_* атрибутите НЕ се во Expert. 751 787 752 788 '''Заклучок:''' Expert е во 3NF ✓ 753 789 754 ==== Tag_Translate(tag_translate_id, tag_ translate_language, tag_value, tag_id) ====790 ==== Tag_Translate(tag_translate_id, tag_value, tag_id, language_id) ==== 755 791 756 792 '''Транзитивни зависности:''' 757 793 * tag_translate_id → tag_id → tag_*? 758 794 * tag_* атрибутите НЕ се во Tag_Translate. 795 * tag_translate_id → language_id → language_value? 796 * language_value НЕ е во Tag_Translate. 759 797 760 798 '''Заклучок:''' Tag_Translate е во 3NF ✓ 761 799 762 ==== Course_Translate(course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id) ====800 ==== Course_Translate(course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id) ==== 763 801 764 802 '''Транзитивни зависности:''' 765 803 * course_translate_id → course_id → course_*? 766 804 * course_* атрибутите НЕ се во Course_Translate. 805 * course_translate_id → language_id → language_value? 806 * language_value НЕ е во Course_Translate. 767 807 768 808 '''Заклучок:''' Course_Translate е во 3NF ✓ 769 809 770 ==== Course_Content_Translate(course_content_translate_id, content_translate_title, co ntent_translate_language, course_content_id) ====810 ==== Course_Content_Translate(course_content_translate_id, content_translate_title, course_content_id, language_id) ==== 771 811 772 812 '''Транзитивни зависности:''' 773 813 * course_content_translate_id → course_content_id → course_content_*? 774 814 * course_content_* атрибутите НЕ се во Course_Content_Translate. 815 * course_content_translate_id → language_id → language_value? 816 * language_value НЕ е во Course_Content_Translate. 775 817 776 818 '''Заклучок:''' Course_Content_Translate е во 3NF ✓ 777 819 778 ==== Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id) ====820 ==== Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id) ==== 779 821 780 822 '''Транзитивни зависности:''' 781 823 * course_lecture_translate_id → course_lecture_id → course_lecture_*? 782 824 * course_lecture_* атрибутите НЕ се во Course_Lecture_Translate. 825 * course_lecture_translate_id → language_id → language_value? 826 * language_value НЕ е во Course_Lecture_Translate. 783 827 784 828 '''Заклучок:''' Course_Lecture_Translate е во 3NF ✓ 785 829 786 ==== User_Course_Progress(user_course_progress_id, progress_ completed, progress_completed_at, enrollment_id, course_lecture_id) ====830 ==== User_Course_Progress(user_course_progress_id, progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id) ==== 787 831 788 832 '''Транзитивни зависности:''' … … 799 843 800 844 '''Заклучок:''' После извлекување на сите парцијални зависности (FD2, FD3, FD4, FD10, FD12, FD14, FD16, FD17), универзалната релација е целосно декомпонирана. Примарниот клуч на Universal_Relation_Shifter_Base_8 е празно множество (∅), што значи дека таа релација повеќе не постои како валидна релација. 801 Останатите функционални зависности (FD1, FD5-FD9, FD11, FD13, FD15 ) **нарушуваат 3NF** бидејќи нивните детерминанти (user_id, course_id, enrollment_id, итн.) не се примарни клучеви на845 Останатите функционални зависности (FD1, FD5-FD9, FD11, FD13, FD15, FD19, FD31) **нарушуваат 3NF** бидејќи нивните детерминанти (user_id, course_id, enrollment_id, account_id, language_id, итн.) не се примарни клучеви на 802 846 Universal_Relation_Shifter_Base_8, туку се независни детерминанти кои треба да формираат посебни релации. 803 847 … … 805 849 806 850 {{{ 807 User(user_id, user_name, user_email, user_login_provider, user_password_hash, user_ verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points)851 User(user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, account_id) 808 852 PK: user_id 809 853 810 Universal_Relation_Shifter_Base_9 = Universal_Relation_Shifter_Base_8 - {user_id, user_name, user_email, user_login_provider, user_password_hash, user_ verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points}854 Universal_Relation_Shifter_Base_9 = Universal_Relation_Shifter_Base_8 - {user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points} 811 855 812 856 Universal_Relation_Shifter_Base_9( 813 expert_id, 857 account_id, account_email, account_password_hash, account_name, 858 language_id, language_value, 814 859 course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price, 815 course_version_id, version_number, version_creat ion_date, version_active,860 course_version_id, version_number, version_created_at, version_is_active, 816 861 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 817 862 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 824 869 825 870 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id 826 827 '''Проверка за dependency preservation:''' FD1 е зачуванаво User871 872 '''Проверка за dependency preservation:''' FD1 и FD18 се зачувани во User 828 873 829 874 === Чекор 6.2: Декомпозиција по FD5 (course_id → course_*) === … … 836 881 837 882 Universal_Relation_Shifter_Base_10( 838 expert_id, 839 course_version_id, version_number, version_creation_date, version_active, 883 account_id, account_email, account_password_hash, account_name, 884 language_id, language_value, 885 course_version_id, version_number, version_created_at, version_is_active, 840 886 enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, 841 887 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 848 894 849 895 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id → course_version_id 850 896 851 897 '''Проверка за dependency preservation:''' FD5 е зачувана во Course 852 898 … … 854 900 855 901 {{{ 856 Enrollment(enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id , payment_id, review_id)902 Enrollment(enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id) 857 903 PK: enrollment_id 858 904 … … 860 906 861 907 Universal_Relation_Shifter_Base_11( 862 expert_id, 863 course_version_id, version_number, version_creation_date, version_active, 908 account_id, account_email, account_password_hash, account_name, 909 language_id, language_value, 910 course_version_id, version_number, version_created_at, version_is_active, 864 911 enrollment_id, 865 912 payment_id, payment_amount, payment_date, payment_method, payment_status, … … 871 918 }}} 872 919 920 '''Забелешка:''' payment_id и review_id се дел од десната страна на FD6 (заради ограничувањата `uq_payment_enrollment` и `uq_review_enrollment`), но не се внесуваат како атрибути во Enrollment. Наместо тоа, врската се чува преку enrollment_id во Payment и Review, што ја избегнува циклична зависност помеѓу трите релации. 921 873 922 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id 874 923 875 924 '''Проверка за dependency preservation:''' FD6 е зачувана во Enrollment 876 925 … … 881 930 PK: payment_id 882 931 883 Universal_Relation_Shifter_Base_12 = Universal_Relation_Shifter_Base_11 - {payment_ amount, payment_date, payment_method, payment_status}932 Universal_Relation_Shifter_Base_12 = Universal_Relation_Shifter_Base_11 - {payment_id, payment_amount, payment_date, payment_method, payment_status} 884 933 885 934 Universal_Relation_Shifter_Base_12( 886 expert_id, 887 course_version_id, version_number, version_creation_date, version_active, 935 account_id, account_email, account_password_hash, account_name, 936 language_id, language_value, 937 course_version_id, version_number, version_created_at, version_is_active, 888 938 enrollment_id, 889 939 review_id, review_rating, review_comment, review_date, … … 895 945 896 946 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id 897 947 898 948 '''Проверка за dependency preservation:''' FD7 е зачувана во Payment 899 949 … … 904 954 PK: review_id 905 955 906 Universal_Relation_Shifter_Base_13 = Universal_Relation_Shifter_Base_12 - {review_ rating, review_comment, review_date}956 Universal_Relation_Shifter_Base_13 = Universal_Relation_Shifter_Base_12 - {review_id, review_rating, review_comment, review_date} 907 957 908 958 Universal_Relation_Shifter_Base_13( 909 expert_id, 910 course_version_id, version_number, version_creation_date, version_active, 959 account_id, account_email, account_password_hash, account_name, 960 language_id, language_value, 961 course_version_id, version_number, version_created_at, version_is_active, 911 962 enrollment_id, 912 963 course_content_id, content_position, … … 917 968 918 969 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id 919 970 920 971 '''Проверка за dependency preservation:''' FD8 е зачувана во Review 921 972 … … 929 980 930 981 Universal_Relation_Shifter_Base_14( 931 expert_id, 932 course_version_id, version_number, version_creation_date, version_active, 982 account_id, account_email, account_password_hash, account_name, 983 language_id, language_value, 984 course_version_id, version_number, version_created_at, version_is_active, 933 985 enrollment_id, 934 986 course_content_id, content_position, … … 939 991 940 992 '''Проверка за lossless join:''' Може да се реконструира преку tag_id 941 993 942 994 '''Проверка за dependency preservation:''' FD9 е зачувана во Tag 943 995 … … 945 997 946 998 {{{ 947 Course_Version(course_version_id, version_number, version_creat ion_date, version_active, course_id)999 Course_Version(course_version_id, version_number, version_created_at, version_is_active, course_id) 948 1000 PK: course_version_id 949 1001 950 Universal_Relation_Shifter_Base_15 = Universal_Relation_Shifter_Base_14 - {course_version_id, version_number, version_creat ion_date, version_active}1002 Universal_Relation_Shifter_Base_15 = Universal_Relation_Shifter_Base_14 - {course_version_id, version_number, version_created_at, version_is_active} 951 1003 952 1004 Universal_Relation_Shifter_Base_15( 953 expert_id, 1005 account_id, account_email, account_password_hash, account_name, 1006 language_id, language_value, 954 1007 enrollment_id, 955 1008 course_content_id, content_position, … … 960 1013 961 1014 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id 962 963 '''Проверка за dependency preservation:''' FD11 е зачуванаво Course_Version1015 1016 '''Проверка за dependency preservation:''' FD11 и FD20 се зачувани во Course_Version 964 1017 965 1018 === Чекор 6.8: Декомпозиција по FD13 (course_content_id → course_content_*) === … … 972 1025 973 1026 Universal_Relation_Shifter_Base_16( 974 expert_id, 1027 account_id, account_email, account_password_hash, account_name, 1028 language_id, language_value, 975 1029 enrollment_id, 976 1030 course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, … … 980 1034 981 1035 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id → course_version_id 982 983 '''Проверка за dependency preservation:''' FD13 е зачуванаво Course_Content1036 1037 '''Проверка за dependency preservation:''' FD13 и FD26 се зачувани во Course_Content 984 1038 985 1039 === Чекор 6.9: Декомпозиција по FD15 (course_lecture_id → course_lecture_*) === … … 992 1046 993 1047 Universal_Relation_Shifter_Base_17( 994 expert_id, 1048 account_id, account_email, account_password_hash, account_name, 1049 language_id, language_value, 995 1050 enrollment_id, 996 1051 tag_id … … 999 1054 1000 1055 '''Проверка за lossless join:''' Може да се реконструира преку enrollment_id → course_version_id → course_content_id 1001 1002 '''Проверка за dependency preservation:''' FD15 е зачувана во Course_Lecture 1003 1004 === Анализа на Universal_Relation_Shifter_Base_17 === 1005 1006 {{{ 1007 Universal_Relation_Shifter_Base_17( 1008 expert_id, 1056 1057 '''Проверка за dependency preservation:''' FD15 и FD27 се зачувани во Course_Lecture 1058 1059 === Чекор 6.10: Декомпозиција по FD19 (account_id → account_*) === 1060 1061 {{{ 1062 Account(account_id, account_email, account_password_hash, account_name) 1063 PK: account_id 1064 1065 Universal_Relation_Shifter_Base_18 = Universal_Relation_Shifter_Base_17 - {account_id, account_email, account_password_hash, account_name} 1066 1067 Universal_Relation_Shifter_Base_18( 1068 language_id, language_value, 1009 1069 enrollment_id, 1010 1070 tag_id … … 1012 1072 }}} 1013 1073 1014 1015 Universal_Relation_Shifter_Base_17 претставува колекција од foreign keys кои треба да се организираат во посебни many-to-many junction tables. 1074 '''Проверка за lossless join:''' Може да се реконструира преку account_id во User и Expert 1075 1076 '''Проверка за dependency preservation:''' FD19 и FD30 се зачувани во Account 1077 1078 === Чекор 6.11: Декомпозиција по FD31 (language_id → language_value) === 1079 1080 {{{ 1081 Language(language_id, language_value) 1082 PK: language_id 1083 1084 Universal_Relation_Shifter_Base_19 = Universal_Relation_Shifter_Base_18 - {language_id, language_value} 1085 1086 Universal_Relation_Shifter_Base_19( 1087 enrollment_id, 1088 tag_id 1089 ) 1090 }}} 1091 1092 '''Проверка за lossless join:''' Може да се реконструира преку language_id во релациите за преводи 1093 1094 '''Проверка за dependency preservation:''' FD31 и FD32 се зачувани во Language 1095 1096 === Анализа на Universal_Relation_Shifter_Base_19 === 1097 1098 {{{ 1099 Universal_Relation_Shifter_Base_19( 1100 enrollment_id, 1101 tag_id 1102 ) 1103 }}} 1104 1105 1106 Universal_Relation_Shifter_Base_19 претставува колекција од foreign keys кои треба да се организираат во посебни many-to-many junction tables. 1016 1107 1017 1108 '''Прашање:''' Дали оваа релација има семантичка смисла? 1018 '''Одговор:''' НЕ! Universal_Relation_Shifter_Base_1 7е само технички резултат од декомпозициите и не претставува ниеден реален бизнис концепт.1109 '''Одговор:''' НЕ! Universal_Relation_Shifter_Base_19 е само технички резултат од декомпозициите и не претставува ниеден реален бизнис концепт. 1019 1110 1020 1111 '''Заклучок од 3NF:''' 1021 Сите функционални зависности (FD1-FD 27) се организирани во релации кои се во 3NF. Universal_Relation_Shifter_Base_17повеќе не постои како валидна релација.1112 Сите функционални зависности (FD1-FD33) се организирани во релации кои се во 3NF. Universal_Relation_Shifter_Base_19 повеќе не постои како валидна релација. 1022 1113 1023 1114 '''Останати врски (many-to-many):''' 1024 Foreign keys во Universal_Relation_Shifter_Base_17укажуваат на many-to-many релации кои НЕ се дефинирани преку функционални зависности, туку преку бизнис логика:1115 Преостанатите foreign keys, заедно со експертот и курсот извлечени во претходните чекори, укажуваат на many-to-many релации кои НЕ се дефинирани преку функционални зависности, туку преку бизнис логика: 1025 1116 1026 1117 * '''User_Tag'''(user_id, tag_id) - корисник има интереси … … 1032 1123 '''Релации креирани преку FD декомпозиција:''' 1033 1124 1034 '''1NF Декомпозиција ( 1 релација):'''1125 '''1NF Декомпозиција (2 релации):''' 1035 1126 ||= Релација =||= Атрибути =||= Примарен клуч =|| 1036 || Course_ What_Will_Be_Learned || course_translate_id, course_what_will_be_learned || (course_translate_id, course_what_will_be_learned) ||1037 || User_ Course_Favorite_Id || user_id, user_course_favorite_id || (user_id, user_course_favorite_id) ||1127 || Course_Translate_What_Will_Be_Learned || course_translate_id, course_what_will_be_learned || (course_translate_id, course_what_will_be_learned) || 1128 || User_Favorite_Course || user_id, course_id || (user_id, course_id) || 1038 1129 1039 1130 '''2NF Декомпозиција (8 релации):''' 1040 1131 ||= Релација =||= Атрибути =||= Примарен клуч =|| 1041 || Verification_Token || verification_token_uuid, token_created_at, token_expire d_at, user_id || verification_token_uuid ||1132 || Verification_Token || verification_token_uuid, token_created_at, token_expires_at, user_id || verification_token_uuid || 1042 1133 || Meeting_Reminder || meeting_reminder_id, meeting_at, meeting_scheduled_at, meeting_sent, meeting_link, user_id || meeting_reminder_id || 1043 || Expert || expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash|| expert_id ||1044 || Tag_Translate || tag_translate_id, tag_ translate_language, tag_value, tag_id || tag_translate_id ||1045 || Course_Translate || course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id || course_translate_id ||1046 || Course_Content_Translate || course_content_translate_id, content_translate_title, co ntent_translate_language, course_content_id || course_content_translate_id ||1047 || Course_Lecture_Translate || course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id || course_lecture_translate_id ||1048 || User_Course_Progress || user_course_progress_id, progress_ completed, progress_completed_at, enrollment_id, course_lecture_id || user_course_progress_id ||1049 1050 '''3NF Декомпозиција ( 9релации):'''1134 || Expert || expert_id, account_id || expert_id || 1135 || Tag_Translate || tag_translate_id, tag_value, tag_id, language_id || tag_translate_id || 1136 || Course_Translate || course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id || course_translate_id || 1137 || Course_Content_Translate || course_content_translate_id, content_translate_title, course_content_id, language_id || course_content_translate_id || 1138 || Course_Lecture_Translate || course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id || course_lecture_translate_id || 1139 || User_Course_Progress || user_course_progress_id, progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id || user_course_progress_id || 1140 1141 '''3NF Декомпозиција (11 релации):''' 1051 1142 ||= Релација =||= Атрибути =||= Примарен клуч =|| 1052 || User || user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points || user_id || 1143 || Account || account_id, account_email, account_password_hash, account_name || account_id || 1144 || User || user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, account_id || user_id || 1145 || Language || language_id, language_value || language_id || 1053 1146 || Course || course_id, course_image_url, course_color, course_difficulty, course_duration_minutes, course_price || course_id || 1054 || Course_Version || course_version_id, version_number, version_creat ion_date, version_active, course_id || course_version_id ||1055 || Enrollment || enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id , payment_id, review_id|| enrollment_id ||1147 || Course_Version || course_version_id, version_number, version_created_at, version_is_active, course_id || course_version_id || 1148 || Enrollment || enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id || enrollment_id || 1056 1149 || Payment || payment_id, payment_amount, payment_date, payment_method, payment_status, enrollment_id || payment_id || 1057 1150 || Review || review_id, review_rating, review_comment, review_date, enrollment_id || review_id || … … 1074 1167 За секоја релација проверуваме: за секоја нетривијална FD X → Y, дали X е суперклуч? 1075 1168 1169 ==== Account ==== 1170 1171 ||= FD =||= Детерминант =||= Суперклуч? =|| 1172 || account_id → сите || account_id || ✓ ДА || 1173 || account_email → сите (FD30) || account_email || ✓ ДА || 1174 1175 '''Account е во BCNF''' ✓ 1176 1177 ==== Language ==== 1178 1179 ||= FD =||= Детерминант =||= Суперклуч? =|| 1180 || language_id → сите || language_id || ✓ ДА || 1181 || language_value → сите (FD32) || language_value || ✓ ДА || 1182 1183 '''Language е во BCNF''' ✓ 1184 1076 1185 ==== Verification_Token ==== 1077 1186 … … 1085 1194 ||= FD =||= Детерминант =||= Суперклуч? =|| 1086 1195 || meeting_reminder_id → сите || meeting_reminder_id || ✓ ДА || 1196 || meeting_link → сите (FD33) || meeting_link || ✓ ДА || 1087 1197 1088 1198 '''Meeting_Reminder е во BCNF''' ✓ … … 1099 1209 ||= FD =||= Детерминант =||= Суперклуч? =|| 1100 1210 || tag_translate_id → сите || tag_translate_id || ✓ ДА || 1211 || (tag_id, language_id) → сите (FD24) || tag_id, language_id || ✓ ДА || 1101 1212 1102 1213 '''Tag_Translate е во BCNF''' ✓ … … 1106 1217 ||= FD =||= Детерминант =||= Суперклуч? =|| 1107 1218 || course_translate_id → сите || course_translate_id || ✓ ДА || 1219 || (course_id, language_id) → сите (FD21) || course_id, language_id || ✓ ДА || 1108 1220 1109 1221 '''Course_Translate е во BCNF''' ✓ … … 1113 1225 ||= FD =||= Детерминант =||= Суперклуч? =|| 1114 1226 || course_content_translate_id → сите || course_content_translate_id || ✓ ДА || 1227 || (course_content_id, language_id) → сите (FD23) || course_content_id, language_id || ✓ ДА || 1115 1228 1116 1229 '''Course_Content_Translate е во BCNF''' ✓ … … 1120 1233 ||= FD =||= Детерминант =||= Суперклуч? =|| 1121 1234 || course_lecture_translate_id → сите || course_lecture_translate_id || ✓ ДА || 1235 || (course_lecture_id, language_id) → сите (FD22) || course_lecture_id, language_id || ✓ ДА || 1122 1236 1123 1237 '''Course_Lecture_Translate е во BCNF''' ✓ … … 1127 1241 ||= FD =||= Детерминант =||= Суперклуч? =|| 1128 1242 || user_course_progress_id → сите || user_course_progress_id || ✓ ДА || 1243 || (enrollment_id, course_lecture_id) → сите (FD25) || enrollment_id, course_lecture_id || ✓ ДА || 1129 1244 1130 1245 '''User_Course_Progress е во BCNF''' ✓ … … 1134 1249 ||= FD =||= Детерминант =||= Суперклуч? =|| 1135 1250 || user_id → сите || user_id || ✓ ДА || 1251 || user_email → сите (FD18) || user_email || ✓ ДА || 1136 1252 1137 1253 '''User е во BCNF''' ✓ … … 1155 1271 ||= FD =||= Детерминант =||= Суперклуч? =|| 1156 1272 || payment_id → сите || payment_id || ✓ ДА || 1273 || enrollment_id → сите (FD6) || enrollment_id || ✓ ДА || 1157 1274 1158 1275 '''Payment е во BCNF''' ✓ … … 1162 1279 ||= FD =||= Детерминант =||= Суперклуч? =|| 1163 1280 || review_id → сите || review_id || ✓ ДА || 1281 || enrollment_id → сите (FD6) || enrollment_id || ✓ ДА || 1164 1282 1165 1283 '''Review е во BCNF''' ✓ … … 1176 1294 ||= FD =||= Детерминант =||= Суперклуч? =|| 1177 1295 || course_version_id → сите || course_version_id || ✓ ДА || 1296 || (course_id, version_number) → сите (FD20) || course_id, version_number || ✓ ДА || 1178 1297 1179 1298 '''Course_Version е во BCNF''' ✓ … … 1183 1302 ||= FD =||= Детерминант =||= Суперклуч? =|| 1184 1303 || course_content_id → сите || course_content_id || ✓ ДА || 1304 || (course_version_id, content_position) → сите (FD26) || course_version_id, content_position || ✓ ДА || 1185 1305 1186 1306 '''Course_Content е во BCNF''' ✓ … … 1190 1310 ||= FD =||= Детерминант =||= Суперклуч? =|| 1191 1311 || course_lecture_id → сите || course_lecture_id || ✓ ДА || 1312 || (course_content_id, lecture_position) → сите (FD27) || course_content_id, lecture_position || ✓ ДА || 1192 1313 1193 1314 '''Course_Lecture е во BCNF''' ✓ … … 1203 1324 1204 1325 {{{ 1205 User_ Course_Favorite_Id(user_id, user_course_favorite_id)1206 - Примарен клуч: user_id, user_course_favorite_id1207 - Кандидат клучеви: user_id, user_course_favorite_id1208 - Надворешни клучеви: user_id 1209 1210 Course_ What_Will_Be_Learned(course_translate_id, course_what_will_be_learned)1326 User_Favorite_Course(user_id, course_id) 1327 - Примарен клуч: user_id, course_id 1328 - Кандидат клучеви: user_id, course_id 1329 - Надворешни клучеви: user_id, course_id 1330 1331 Course_Translate_What_Will_Be_Learned(course_translate_id, course_what_will_be_learned) 1211 1332 - Примарен клуч: course_translate_id, course_what_will_be_learned 1212 1333 - Кандидат клучеви: course_translate_id, course_what_will_be_learned 1213 1334 - Надворешни клучеви: course_translate_id 1214 1335 1215 User(user_id, user_name, user_email, user_login_provider, user_password_hash, user_verified, user_profile_complete, user_used_free_consultation, user_company_size, user_work_position, user_points) 1336 Account(account_id, account_email, account_password_hash, account_name) 1337 - Примарен клуч: account_id 1338 - Кандидат клучеви: account_id, account_email 1339 - Надворешни клучеви: - 1340 1341 User(user_id, user_name, user_email, user_login_provider, user_password_hash, user_is_verified, user_is_profile_complete, user_has_used_free_consultation, user_company_size, user_work_position, user_points, account_id) 1216 1342 - Примарен клуч: user_id 1217 - Кандидат клучеви: user_id, user_email 1343 - Кандидат клучеви: user_id, user_email, account_id 1344 - Надворешни клучеви: account_id 1345 1346 Expert(expert_id, account_id) 1347 - Примарен клуч: expert_id 1348 - Кандидат клучеви: expert_id, account_id 1349 - Надворешни клучеви: account_id 1350 1351 Language(language_id, language_value) 1352 - Примарен клуч: language_id 1353 - Кандидат клучеви: language_id, language_value 1218 1354 - Надворешни клучеви: - 1219 1355 1220 Expert(expert_id, expert_name, expert_email, expert_login_provider, expert_password_hash) 1221 - Примарен клуч: expert_id 1222 - Кандидат клучеви: expert_id, expert_email 1223 - Надворешни клучеви: - 1224 1225 Verification_Token(verification_token_uuid, token_created_at, token_expired_at, user_id) 1356 Verification_Token(verification_token_uuid, token_created_at, token_expires_at, user_id) 1226 1357 - Примарен клуч: verification_token_uuid 1227 1358 - Кандидат клучеви: verification_token_uuid … … 1233 1364 - Надворешни клучеви: user_id 1234 1365 1235 Enrollment(enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id , payment_id, review_id)1366 Enrollment(enrollment_id, enrollment_status, enrollment_purchase_date, enrollment_activation_date, enrollment_completion_date, user_id, course_version_id) 1236 1367 - Примарен клуч: enrollment_id 1237 - Кандидат клучеви: enrollment_id 1238 - Надворешни клучеви: user_id, course_version_id , payment_id, review_id1368 - Кандидат клучеви: enrollment_id, (user_id, course_version_id) 1369 - Надворешни клучеви: user_id, course_version_id 1239 1370 1240 1371 Payment(payment_id, payment_amount, payment_date, payment_method, payment_status, enrollment_id) 1241 1372 - Примарен клуч: payment_id 1242 - Кандидат клучеви: payment_id 1373 - Кандидат клучеви: payment_id, enrollment_id 1243 1374 - Надворешни клучеви: enrollment_id 1244 1375 1245 1376 Review(review_id, review_rating, review_comment, review_date, enrollment_id) 1246 1377 - Примарен клуч: review_id 1247 - Кандидат клучеви: review_id 1378 - Кандидат клучеви: review_id, enrollment_id 1248 1379 - Надворешни клучеви: enrollment_id 1249 1380 1250 Course_Version(course_version_id, version_number, version_creat ion_date, version_active, course_id)1381 Course_Version(course_version_id, version_number, version_created_at, version_is_active, course_id) 1251 1382 - Примарен клуч: course_version_id 1252 - Кандидат клучеви: course_version_id 1383 - Кандидат клучеви: course_version_id, (course_id, version_number) 1253 1384 - Надворешни клучеви: course_id 1254 1385 … … 1258 1389 - Надворешни клучеви: - 1259 1390 1260 Course_Translate(course_translate_id, course_t ranslate_language, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id)1391 Course_Translate(course_translate_id, course_title_short, course_title, course_description_short, course_description, course_description_long, course_id, language_id) 1261 1392 - Примарен клуч: course_translate_id 1262 - Кандидат клучеви: course_translate_id 1263 - Надворешни клучеви: course_id 1393 - Кандидат клучеви: course_translate_id, (course_id, language_id) 1394 - Надворешни клучеви: course_id, language_id 1264 1395 1265 1396 Course_Content(course_content_id, content_position, course_version_id) 1266 1397 - Примарен клуч: course_content_id 1267 - Кандидат клучеви: course_content_id 1398 - Кандидат клучеви: course_content_id, (course_version_id, content_position) 1268 1399 - Надворешни клучеви: course_version_id 1269 1400 1270 Course_Content_Translate(course_content_translate_id, content_translate_title, co ntent_translate_language, course_content_id)1401 Course_Content_Translate(course_content_translate_id, content_translate_title, course_content_id, language_id) 1271 1402 - Примарен клуч: course_content_translate_id 1272 - Кандидат клучеви: course_content_translate_id 1273 - Надворешни клучеви: course_content_id 1403 - Кандидат клучеви: course_content_translate_id, (course_content_id, language_id) 1404 - Надворешни клучеви: course_content_id, language_id 1274 1405 1275 1406 Course_Lecture(course_lecture_id, lecture_duration_minutes, lecture_position, lecture_content_type, course_content_id) 1276 1407 - Примарен клуч: course_lecture_id 1277 - Кандидат клучеви: course_lecture_id 1408 - Кандидат клучеви: course_lecture_id, (course_content_id, lecture_position) 1278 1409 - Надворешни клучеви: course_content_id 1279 1410 1280 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_ language, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id)1411 Course_Lecture_Translate(course_lecture_translate_id, lecture_title, lecture_content_file_name, lecture_description, lecture_content_text, course_lecture_id, language_id) 1281 1412 - Примарен клуч: course_lecture_translate_id 1282 - Кандидат клучеви: course_lecture_translate_id 1283 - Надворешни клучеви: course_lecture_id 1284 1285 User_Course_Progress(user_course_progress_id, progress_ completed, progress_completed_at, enrollment_id, course_lecture_id)1413 - Кандидат клучеви: course_lecture_translate_id, (course_lecture_id, language_id) 1414 - Надворешни клучеви: course_lecture_id, language_id 1415 1416 User_Course_Progress(user_course_progress_id, progress_is_completed, progress_completed_at, enrollment_id, course_lecture_id) 1286 1417 - Примарен клуч: user_course_progress_id 1287 - Кандидат клучеви: user_course_progress_id 1418 - Кандидат клучеви: user_course_progress_id, (enrollment_id, course_lecture_id) 1288 1419 - Надворешни клучеви: enrollment_id, course_lecture_id 1289 1420 … … 1293 1424 - Надворешни клучеви: - 1294 1425 1295 Tag_Translate(tag_translate_id, tag_ translate_language, tag_value, tag_id)1426 Tag_Translate(tag_translate_id, tag_value, tag_id, language_id) 1296 1427 - Примарен клуч: tag_translate_id 1297 - Кандидат клучеви: tag_translate_id 1298 - Надворешни клучеви: tag_id 1428 - Кандидат клучеви: tag_translate_id, (tag_id, language_id) 1429 - Надворешни клучеви: tag_id, language_id 1299 1430 1300 1431 User_Tag(user_id, tag_id) … … 1316 1447 === 8.2 Дискусија на разликите од моделот во Фаза P2 === 1317 1448 1318 Преку процесот на нормализација, тргнувајќи од една универзална релација, дојдовме до '''2 2релации'''1319 (1 7од функционални зависности + 3 many-to-many junction tables + 2 multi-value tables). Споредбата со концептуалниот модел1449 Преку процесот на нормализација, тргнувајќи од една универзална релација, дојдовме до '''24 релации''' 1450 (19 од функционални зависности + 3 many-to-many junction tables + 2 multi-value tables). Споредбата со концептуалниот модел 1320 1451 од Фаза P2 покажува следно: 1321 1452 … … 1325 1456 1326 1457 1. '''User''' - идентична структура и атрибути 1327 2. '''Expert''' - идентична структура и атрибути 1328 3. '''Course''' - идентична структура и атрибути 1329 4. '''Course_Version''' - идентична структура и атрибути 1330 5. '''Enrollment''' - идентична структура и атрибути 1331 6. '''Payment''' - идентична структура и атрибути (one-to-one со Enrollment) 1332 7. '''Review''' - идентична структура и атрибути (one-to-one со Enrollment) 1333 8. '''Tag''' - идентична структура и атрибути 1334 9. '''Course_Translate''' - идентична структура и атрибути 1335 10. '''Course_Content''' - идентична структура и атрибути 1336 11. '''Course_Content_Translate''' - идентична структура и атрибути 1337 12. '''Course_Lecture''' - идентична структура и атрибути 1338 13. '''Course_Lecture_Translate''' - идентична структура и атрибути 1339 14. '''Tag_Translate''' - идентична структура и атрибути 1340 15. '''Verification_Token''' - идентична структура и атрибути 1341 16. '''Meeting_Reminder''' - идентична структура и атрибути 1342 17. '''User_Course_Progress''' - идентична структура и атрибути 1458 2. '''Course''' - идентична структура и атрибути 1459 3. '''Course_Version''' - идентична структура и атрибути 1460 4. '''Enrollment''' - идентична структура и атрибути 1461 5. '''Payment''' - идентична структура и атрибути (one-to-one со Enrollment) 1462 6. '''Review''' - идентична структура и атрибути (one-to-one со Enrollment) 1463 7. '''Tag''' - идентична структура и атрибути 1464 8. '''Course_Translate''' - идентична структура и атрибути 1465 9. '''Course_Content''' - идентична структура и атрибути 1466 10. '''Course_Content_Translate''' - идентична структура и атрибути 1467 11. '''Course_Lecture''' - идентична структура и атрибути 1468 12. '''Course_Lecture_Translate''' - идентична структура и атрибути 1469 13. '''Tag_Translate''' - идентична структура и атрибути 1470 14. '''Verification_Token''' - идентична структура и атрибути 1471 15. '''Meeting_Reminder''' - идентична структура и атрибути 1472 16. '''User_Course_Progress''' - идентична структура и атрибути 1473 1474 ==== Релации кои се разликуваат од P2 ==== 1475 1476 17. '''Account''' - нова релација која не постоеше во концептуалниот модел. Атрибутите за најава (email, password_hash, name) беа дуплирани во User и Expert, па се издвоени во заеднички ентитет. 1477 18. '''Expert''' - се разликува од P2. Атрибутите expert_name, expert_email, expert_login_provider и expert_password_hash преминаа во Account, па Expert останува само со expert_id и надворешниот клуч account_id. 1478 19. '''Language''' - нова релација која не постоеше во концептуалниот модел. Јазикот беше текстуален атрибут во четирите релации за преводи, а сега е самостоен ентитет со надворешни клучеви language_id. 1343 1479 1344 1480 ==== Many-to-Many релации ==== 1345 1481 1346 18. '''Expert_Course''' - junction table за many-to-many релација помеѓу Expert и Course1347 19. '''Course_Tag''' - junction table за many-to-many релација помеѓу Course и Tag1348 2 0. '''User_Tag''' - junction table за many-to-many релација помеѓу User и Tag1482 20. '''Expert_Course''' - junction table за many-to-many релација помеѓу Expert и Course 1483 21. '''Course_Tag''' - junction table за many-to-many релација помеѓу Course и Tag 1484 22. '''User_Tag''' - junction table за many-to-many релација помеѓу User и Tag 1349 1485 1350 1486 ==== Релација со мултивредносен атрибут ==== 1351 1487 1352 2 1. '''Course_What_Will_Be_Learned''' - беше дел од Course_Translate во концептуалниот модел, но се издвои во посебна релација во 1NF декомпозицијата поради мултивредносна природа (еденкурс има повеќе "what will be learned" ставки).1353 2 2. '''User_Course_Favorite_Id''' - беше дел од User во концептуалниот модел, но се издвои во посебна релација во 1NF декомпозицијата поради мултивредносна природа (еден корисник има повеќе "course favorite id" ставки).1488 23. '''Course_Translate_What_Will_Be_Learned''' - беше дел од Course_Translate во концептуалниот модел, но се издвои во посебна релација во 1NF декомпозицијата поради мултивредносна природа (еден превод на курс има повеќе "what will be learned" ставки). 1489 24. '''User_Favorite_Course''' - беше дел од User во концептуалниот модел, но се издвои во посебна релација во 1NF декомпозицијата поради мултивредносна природа (еден корисник има повеќе омилени курсеви). 1354 1490 1355 1491 ==== Клучни наоди ==== 1356 1492 1357 1. '''Процесот на нормализација го потврди дизајнот''' - секоја декомпозиција базирана на функционалните зависности резултираше со релација која одговара на ентитет од оригиналниот модел.1358 1359 2. '''Клучот на универзалната релација''' - примарниот клуч беше идентификуван како композитен клуч од 8 атрибути: {verification_token_uuid, meeting_reminder_id, user_course_progress_id, expert_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id, course_what_will_be_learned}. Овој клуч беше идентификуван преку анализа на функционалните зависности и класификација лева/десна страна на атрибутите.1493 1. '''Процесот на нормализација го потврди најголемиот дел од дизајнот''' - секоја декомпозиција базирана на функционалните зависности резултираше со релација која одговара на ентитет од оригиналниот модел, освен во три случаи: Account, Language и намалениот Expert. 1494 1495 2. '''Клучот на универзалната релација''' - примарниот клуч беше идентификуван како композитен клуч од 10 атрибути: {verification_token_uuid, meeting_reminder_id, expert_id, course_what_will_be_learned, user_favorite_course_ids, user_course_progress_id, course_lecture_translate_id, course_content_translate_id, course_translate_id, tag_translate_id}. Овој клуч беше идентификуван преку анализа на функционалните зависности и класификација лева/десна страна на атрибутите. По 1NF декомпозицијата, атрибутите course_what_will_be_learned и user_favorite_course_ids се извлекуваат, па клучот на базната релација се сведува на 8 атрибути. 1360 1496 1361 1497 3. '''Декомпозицијата е lossless''' - на секој чекор од процесот на нормализација, оригиналната информација може да се реконструира преку JOIN операции на заедничките атрибути (foreign keys). 1362 1498 1363 4. '''Сите функционални зависности се зачувани''' - сите 29 функционални зависности (FD1-FD29) се зачувани во соодветните релации, што значи дека ограничувањата можат да се проверуваат без потреба од скапи JOIN операции.1499 4. '''Сите функционални зависности се зачувани''' - сите 33 функционални зависности (FD1-FD33) се зачувани во соодветните релации, што значи дека ограничувањата можат да се проверуваат без потреба од скапи JOIN операции. 1364 1500 1365 1501 5. '''Many-to-many релации''' - junction tables (Expert_Course, Course_Tag, User_Tag) не произлегуваат од функционални зависности, туку од ER моделот и бизнис логиката. Овие релации немаат свои атрибути освен composite primary key од два foreign keys. 1366 1502 1503 6. '''Издвојувањето на Account''' - оваа релација произлезе од функционалните зависности FD19 и FD30, кои не постоеја во P2. Во P2 атрибутите за најава беа дуплирани во User и Expert, што претставува редундантност: промена на лозинка би барала ажурирање на две релации. 1504 1367 1505 ==== Заклучок ==== 1368 1506 1369 Процесот на нормализација ''' целосно го потврди дизајнот''' од концептуалната фаза (P2). Ова покажува дека оригиналниот ER модел беше креиран според принципите на добра база на податоци (минимална редундантност, јасна сепарација на концепти, правилна идентификација на ентитети и релации).1370 1371 '''Финалниот релационен модел ќе биде идентичен со моделот од Фаза P2'''.1507 Процесот на нормализација '''го потврди најголемиот дел од дизајнот''' од концептуалната фаза (P2), но воведе и три разлики: издвојување на Account, издвојување на Language и намалување на Expert. Ова покажува дека оригиналниот ER модел беше во голема мера креиран според принципите на добра база на податоци (минимална редундантност, јасна сепарација на концепти, правилна идентификација на ентитети и релации), но дека дуплираните атрибути за најава и текстуалниот атрибут за јазик беа извори на редундантност кои нормализацијата ги отстрани. 1508 1509 '''Финалниот релационен модел се разликува од моделот од Фаза P2 во три релации: Account, Language и Expert'''.
