| 17 | | user_updated_at, story_id, mature_content, short_description, image, story_content, |
| 18 | | story_created_at, story_updated_at, status, chapter_id, chapter_number, chapter_name, |
| 19 | | title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, |
| 20 | | chapter_updated_at, genre_id, genre_name, list_id, list_name, list_content, is_public, |
| 21 | | list_created_at, list_updated_at, added_at, notification_id, notification_content, is_read, |
| 22 | | type, link, notification_created_at, content_type, suggestion_id, original_text, |
| 23 | | suggested_text, accepted, applied_at, suggestion_created_at, suggestion_type, comment_id, |
| 24 | | comment_content, comment_created_at, comment_updated_at, roles, permission_level, |
| 25 | | collab_created_at, like_created_at} |
| | 18 | user_updated_at, assigned_at, joined_at, bio, story_id, title, mature_content, |
| | 19 | short_description, image, story_content, status, story_created_at, story_updated_at, |
| | 20 | chapter_id, chapter_number, chapter_name, chapter_content, word_count, rating, |
| | 21 | published_at, view_count, chapter_created_at, chapter_updated_at, genre_id, genre_name, |
| | 22 | list_id, list_name, list_content, is_public, list_created_at, list_updated_at, added_at, |
| | 23 | notification_id, notification_content, content_type, is_read, link, notification_created_at, |
| | 24 | suggestion_id, original_text, suggested_text, suggestion_type, accepted, applied_at, |
| | 25 | suggestion_created_at, comment_id, comment_content, comment_created_at, comment_updated_at, |
| | 26 | role, permission_level, collab_created_at, liked_at} |
| 46 | | user_id+ = {user_id, username, email, user_name, surname, password,user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 47 | | |
| 48 | | username+ = {username, user_id, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 49 | | |
| 50 | | email+ = {email, user_id, username, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 51 | | |
| 52 | | story_id+ = {story_id, mature_content, short_description, image, story_content,story_title, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 53 | | |
| 54 | | chapter_id+ = {chapter_id, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, story_id, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 55 | | |
| 56 | | {story_id, chapter_number}+ = {story_id, chapter_number, chapter_id, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 57 | | |
| 58 | | genre_id+ = {genre_id, genre_name} → Does NOT contain all attributes of R |
| 59 | | |
| 60 | | genre_name+ = {genre_name, genre_id} → Does NOT contain all attributes of R |
| 61 | | |
| 62 | | list_id+ = {list_id, list_name, list_content, is_public, user_id, list_created_at, list_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 63 | | |
| 64 | | notification_id+ = {notification_id, notification_content, is_read, recipient_user_id, type, link, notification_created_at} → Does NOT contain all attributes of R |
| 65 | | |
| 66 | | suggestion_id+ = {suggestion_id, original_text, suggested_text, accepted, suggestion_created_at, applied_at, story_id, mature_content, short_description, image, story_content, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 67 | | |
| 68 | | comment_id+ = {comment_id, comment_content, user_id, story_id, comment_created_at, comment_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 69 | | |
| 70 | | {user_id, story_id}+ = {user_id, story_id, like_created_at, collab_created_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 71 | | |
| 72 | | {list_id, story_id}+ = {list_id, story_id, added_at, list_name, list_content, is_public, list_created_at, list_updated_at, mature_content, short_description, image, story_content,user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| 73 | | |
| 74 | | {chapter_id, genre_id, list_id, notification_id, suggestion_id, comment_id, status, content_type, suggestion_type, roles, permission_level}+ = {chapter_id, genre_id, list_id, notification_id, suggestion_id, comment_id, status, content_type, suggestion_type, roles, permission_level, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, story_id, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at, like_created_at, collab_created_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at, added_at, notification_content, is_read, recipient_user_id, type, link, notification_created_at, original_text, suggested_text, accepted, suggestion_created_at, applied_at, comment_content, comment_created_at, comment_updated_at} → contains all attributes of R → This is the Candidate Key (Primary Key) of R, this is only candidate key because it covers all attributes of R,it's minimal and no alternative exists(every attribute group is independent). |
| | 47 | |
| | 48 | user_id+ = {user_id, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 49 | |
| | 50 | username+ = {username, user_id, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 51 | |
| | 52 | email+ = {email, user_id, username, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 53 | |
| | 54 | story_id+ = {story_id, title, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 55 | |
| | 56 | chapter_id+ = {chapter_id, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, story_id, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 57 | |
| | 58 | {story_id, chapter_number}+ = {story_id, chapter_number, chapter_id, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 59 | |
| | 60 | genre_id+ = {genre_id, genre_name} → Does NOT contain all attributes of R |
| | 61 | |
| | 62 | genre_name+ = {genre_name, genre_id} → Does NOT contain all attributes of R |
| | 63 | |
| | 64 | list_id+ = {list_id, list_name, list_content, is_public, user_id, list_created_at, list_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 65 | |
| | 66 | notification_id+ = {notification_id, notification_content, content_type, is_read, user_id, story_id, link, notification_created_at, username, email, user_name, surname, password, user_created_at, user_updated_at, title, mature_content, short_description, image, story_content, status, story_created_at, story_updated_at} → Does NOT contain all attributes of R |
| | 67 | |
| | 68 | suggestion_id+ = {suggestion_id, original_text, suggested_text, suggestion_type, accepted, suggestion_created_at, applied_at, story_id, title, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 69 | |
| | 70 | comment_id+ = {comment_id, comment_content, user_id, story_id, comment_created_at, comment_updated_at, title, mature_content, short_description, image, story_content, status, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 71 | |
| | 72 | {user_id, story_id}+ = {user_id, story_id, liked_at, role, permission_level, collab_created_at, title, mature_content, short_description, image, story_content, status, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 73 | |
| | 74 | {list_id, story_id}+ = {list_id, story_id, added_at, list_name, list_content, is_public, list_created_at, list_updated_at, title, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at} → Does NOT contain all attributes of R |
| | 75 | |
| | 76 | {chapter_id, genre_id, list_id, notification_id, suggestion_id, comment_id}+ = {chapter_id, genre_id, list_id, notification_id, suggestion_id, comment_id, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, story_id, chapter_created_at, chapter_updated_at, mature_content, short_description, image, story_content, status, user_id, story_created_at, story_updated_at, username, email, user_name, surname, password, user_created_at, user_updated_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at, notification_content, content_type, is_read, link, notification_created_at, original_text, suggested_text, suggestion_type, accepted, suggestion_created_at, applied_at, comment_content, comment_created_at, comment_updated_at, liked_at, role, permission_level, collab_created_at, added_at} → contains all attributes of R except assigned_at, joined_at, bio (which are partial attributes applying only to the respective USER subtype and are not covered by any FD in this set) → This is the minimal Candidate Key of R. Note: story_id and user_id, although present in several individual FDs, are transitively derivable through chapter_id (chapter_id → story_id → user_id) and are therefore redundant as explicit key components. |
| 146 | | Step 2: Decompose R₁ → STORY + R₂ — common attribute: story_id → primary key of STORY |
| 147 | | |
| 148 | | R₂ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content,story_title, story_created_at, story_updated_at} |
| 149 | | Step 3: Decompose R₂ → CHAPTER + R₃ — common attribute: chapter_id → primary key of CHAPTER |
| 150 | | |
| 151 | | R₃ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at} |
| 152 | | Step 4: Decompose R₃ → GENRE + R₄ — common attribute: genre_id → primary key of GENRE |
| 153 | | |
| 154 | | R₄ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, genre_name} |
| 155 | | Step 5: Decompose R₄ → READING_LIST + R₅ — common attribute: list_id → primary key of READING_LIST |
| 156 | | |
| 157 | | R₅ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at} |
| 158 | | Step 6: Decompose R₅ → NOTIFICATION + R₆ — common attribute: notification_id → primary key of NOTIFICATION |
| 159 | | |
| 160 | | R₆ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at, notification_content, is_read, type, link, notification_created_at} |
| 161 | | Step 7: Decompose R₆ → AI_SUGGESTION + R₇ — common attribute: suggestion_id → primary key of AI_SUGGESTION |
| 162 | | |
| 163 | | R₇ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at, notification_content, is_read, type, link, notification_created_at, original_text, suggested_text, accepted, suggestion_created_at, applied_at} |
| 164 | | Step 8: Decompose R₇ → COMMENT + R₈ — common attribute: comment_id → primary key of COMMENT |
| 165 | | |
| 166 | | R₈ = All attributes of R, except: {username, email, user_name, surname, password, user_created_at, user_updated_at, mature_content, short_description, image, story_content, story_created_at, story_updated_at, chapter_number, chapter_name, title, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at, genre_name, list_name, list_content, is_public, list_created_at, list_updated_at, notification_content, is_read, type, link, notification_created_at, original_text, suggested_text, accepted, suggestion_created_at, applied_at, comment_content, comment_created_at, comment_updated_at} |
| 167 | | Step 9: Decompose R₈ → STATUS + R₉ — common attribute: story_id → primary key of STORY |
| 168 | | |
| 169 | | R₉ = All attributes of R, except: {... same as R₈ ..., status} |
| 170 | | Step 10: Decompose R₉ → CONTENT_TYPE + R₁₀ — common attribute: notification_id → primary key of NOTIFICATION |
| 171 | | |
| 172 | | R₁₀ = All attributes of R, except: {... same as R₉ ..., content_type} |
| 173 | | Step 11: Decompose R₁₀ → SUGGESTION_TYPE + R₁₁ — common attribute: suggestion_id → primary key of AI_SUGGESTION |
| 174 | | |
| 175 | | R₁₁ = All attributes of R, except: {... same as R₁₀ ..., suggestion_type} |
| 176 | | Step 12: Decompose R₁₁ → LIKES + R₁₂ — common attributes: {user_id, story_id} → primary key of LIKES |
| 177 | | |
| 178 | | R₁₂ = All attributes of R, except: {... same as R₁₁ ..., like_created_at} |
| 179 | | Step 13: Decompose R₁₂ → COLLABORATION + R₁₃ — common attributes: {user_id, story_id} → primary key of COLLABORATION |
| 180 | | |
| 181 | | R₁₃ = All attributes of R, except: {... same as R₁₂ ..., collab_created_at} |
| 182 | | Step 14: Decompose R₁₃ → ROLES + R₁₄ — common attributes: {user_id, story_id} → primary key of ROLES |
| 183 | | |
| 184 | | R₁₄ = All attributes of R, except: {... same as R₁₃ ..., roles} |
| 185 | | Step 15: Decompose R₁₄ → PERMISSION_LEVEL + R₁₅ — common attributes: {user_id, story_id} → primary key of PERMISSION_LEVEL |
| 186 | | |
| 187 | | R₁₅ = All attributes of R, except: {... same as R₁₄ ..., permission_level |
| 188 | | Step 16: Decompose R₁₅ → HAS_GENRE + R₁₆ — common attributes: {story_id, genre_id} → primary key of HAS_GENRE |
| 189 | | |
| 190 | | R₁₆ = All attributes of R, except: {... same as R₁₅ ..., genre_id} |
| 191 | | Step 17: Decompose R₁₆ → READING_LIST_ITEMS + R₁₇ — common attributes: {list_id, story_id} → primary key of READING_LIST_ITEMS |
| 192 | | |
| 193 | | R₁₇ = All attributes of R, except: {... same as R₁₆ ..., added_at |
| 194 | | Step 18: Decompose R₁₇ → NOTIFY + R₁₈ — common attributes: {user_id, story_id, notification_id} → primary key of NOTIFY |
| 195 | | |
| 196 | | R₁₈ = {suggestion_id, story_id, chapter_id} — only the attributes of NEED_APPROVAL remain |
| 197 | | Step 19: Decompose R₁₈ → NEED_APPROVAL (final relation) — common attributes: {suggestion_id, story_id, chapter_id} → primary key of NEED_APPROVAL |
| 198 | | |
| 199 | | R₁₉ = ∅ — all attributes fully decomposed |
| | 145 | |
| | 146 | Step 2: Decompose R₁ → ADMIN + R₂ — common attribute: user_id → primary key of ADMIN |
| | 147 | R₂ = All attributes of R₁, except: {assigned_at} |
| | 148 | |
| | 149 | Step 3: Decompose R₂ → REGULAR_USER + R₃ — common attribute: user_id → primary key of REGULAR_USER |
| | 150 | R₃ = All attributes of R₂, except: {joined_at} |
| | 151 | |
| | 152 | Step 4: Decompose R₃ → WRITER + R₄ — common attribute: user_id → primary key of WRITER |
| | 153 | R₄ = All attributes of R₃, except: {bio} |
| | 154 | |
| | 155 | Step 5: Decompose R₄ → STORY + R₅ — common attribute: story_id → primary key of STORY |
| | 156 | R₅ = All attributes of R₄, except: {title, mature_content, short_description, image, story_content, status, story_created_at, story_updated_at} |
| | 157 | |
| | 158 | Step 6: Decompose R₅ → CHAPTER + R₆ — common attribute: chapter_id → primary key of CHAPTER |
| | 159 | R₆ = All attributes of R₅, except: {chapter_number, chapter_name, chapter_content, word_count, rating, published_at, view_count, chapter_created_at, chapter_updated_at} |
| | 160 | (note: title is shared with STORY and is already removed in Step 5; it appears once in R as a single attribute name, resolved together with the STORY decomposition) |
| | 161 | |
| | 162 | Step 7: Decompose R₆ → GENRE + R₇ — common attribute: genre_id → primary key of GENRE |
| | 163 | R₇ = All attributes of R₆, except: {genre_name} |
| | 164 | |
| | 165 | Step 8: Decompose R₇ → READING_LIST + R₈ — common attribute: list_id → primary key of READING_LIST |
| | 166 | R₈ = All attributes of R₇, except: {list_name, list_content, is_public, list_created_at, list_updated_at} |
| | 167 | |
| | 168 | Step 9: Decompose R₈ → NOTIFICATION + R₉ — common attribute: notification_id → primary key of NOTIFICATION |
| | 169 | R₉ = All attributes of R₈, except: {notification_content, content_type, is_read, link, notification_created_at} |
| | 170 | |
| | 171 | Step 10: Decompose R₉ → AI_SUGGESTION + R₁₀ — common attribute: suggestion_id → primary key of AI_SUGGESTION |
| | 172 | R₁₀ = All attributes of R₉, except: {original_text, suggested_text, suggestion_type, accepted, suggestion_created_at, applied_at} |
| | 173 | |
| | 174 | Step 11: Decompose R₁₀ → COMMENT + R₁₁ — common attribute: comment_id → primary key of COMMENT |
| | 175 | R₁₁ = All attributes of R₁₀, except: {comment_content, comment_created_at, comment_updated_at} |
| | 176 | |
| | 177 | Step 12: Decompose R₁₁ → LIKES + R₁₂ — common attributes: {user_id, story_id} → primary key of LIKES |
| | 178 | R₁₂ = All attributes of R₁₁, except: {liked_at} |
| | 179 | |
| | 180 | Step 13: Decompose R₁₂ → COLLABORATION + R₁₃ — common attributes: {user_id, story_id} → primary key of COLLABORATION |
| | 181 | R₁₃ = All attributes of R₁₂, except: {role, permission_level, collab_created_at} |
| | 182 | |
| | 183 | Step 14: Decompose R₁₃ → HAS_GENRE + R₁₄ — common attributes: {story_id, genre_id} → primary key of HAS_GENRE |
| | 184 | R₁₄ = All attributes of R₁₃, except: {} (HAS_GENRE has no non-key attributes; story_id and genre_id remain in R₁₄ as they are also part of other relations' keys) |
| | 185 | |
| | 186 | Step 15: Decompose R₁₄ → READING_LIST_ITEMS + R₁₅ — common attributes: {list_id, story_id} → primary key of READING_LIST_ITEMS |
| | 187 | R₁₅ = All attributes of R₁₄, except: {added_at} |
| | 188 | |
| | 189 | Step 16: Decompose R₁₅ → NEED_APPROVAL (final relation) — common attributes: {suggestion_id, story_id, chapter_id} → primary key of NEED_APPROVAL |
| | 190 | R₁₆ = ∅ — all attributes fully decomposed |