1 | | |
2 | | == Систематска анализа и нормализација на базата Synergymed |
3 | | |
4 | | ---- |
5 | | Целосна и детална анализа на сите ентитети и релации во базата SynergyMed.\\ |
6 | | |
7 | | Целта е да се докаже, со користење на функционални зависности, покривачи и суперклучеви, дека секоја релација ја задоволува Boyce–Codd Normal Form (BCNF). |
8 | | |
9 | | == Нормализација |
10 | | Првичниот дизајн не ја содржеше релацијата **Facility**. Наместо тоа, релацијата **Inventory** беше директно врзана со **Company**, според следниот модел:\\ |
11 | | |
12 | | Inventory(id, company_id, code, ...)\\ |
13 | | |
14 | | Функционалните зависности беа:\\ |
15 | | - id → {company_id, code, ...}\\ |
16 | | - code → id\\ |
17 | | - company_id → code \\ |
18 | | \\ |
19 | | Последната зависност company_id → code претставува проблем: левата страна (company_id) не е суперклуч, а детерминира друг атрибут. Ова е директно прекршување на условот за BCNF. |
20 | | |
21 | | **Доказ преку покривач:**\\ |
22 | | - (company_id)⁺ = {company_id, code} \\ |
23 | | → не го покрива целиот сет на атрибути во Inventory. \\ |
24 | | - Значи company_id не е суперклуч, а сепак детерминира code. \\ |
25 | | - Следува: Inventory **не е во BCNF**.\\ |
26 | | |
27 | | ---- |
28 | | |
29 | | == Декомпозиција за да се постигне BCNF |
30 | | |
31 | | За да се елиминира прекршувањето, воведовме нова релација **Facility**. \\ |
32 | | Сега добиваме:\\ |
33 | | \\ |
34 | | Facility(id, company_id, facility_name, code) \\ |
35 | | Inventory(id, facility_id, ...)\\ |
36 | | \\ |
37 | | Нови функционални зависности:\\ |
38 | | - Во Facility: \\ |
39 | | id → {company_id, facility_name, code} \\ |
40 | | code → id \\ |
41 | | → во двата случаи левата страна е клуч → Facility е во BCNF. \\ |
42 | | \\ |
43 | | - Во Inventory: \\ |
44 | | id → {facility_id, ...} \\ |
45 | | facility_id е уникатен → facility_id → id \\ |
46 | | → левата страна секогаш е клуч → Inventory е во BCNF.\\ |
47 | | |
48 | | Со оваа декомпозиција овозможивме и полесно скалирање на апликацијата во иднина, што воедно беше и наша цел. |
49 | | |
50 | | ---- |
51 | | |
52 | | == Идентификување на суперклучеви и нивните покривачи после нормализацијата |
53 | | |
54 | | **Users**\\ |
55 | | Суперклуч: id\\ |
56 | | id⁺ = {id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth}\\ |
57 | | \\ |
58 | | Суперклуч: username\\ |
59 | | username⁺ = {username, id, first_name, last_name, hashed_password, e_mail, gender, date_created, date_of_birth}\\ |
60 | | \\ |
61 | | Суперклуч: e_mail\\ |
62 | | e_mail⁺ = {e_mail, id, first_name, last_name, username, hashed_password, gender, date_created, date_of_birth}\\ |
63 | | \\ |
64 | | **Client**\\ |
65 | | Суперклуч: user_id\\ |
66 | | user_id⁺ = {user_id, is_verified}\\ |
67 | | \\ |
68 | | **Pharmacist**\\ |
69 | | Суперклуч: user_id\\ |
70 | | user_id⁺ = {user_id}\\ |
71 | | \\ |
72 | | **Admin**\\ |
73 | | Суперклуч: user_id\\ |
74 | | user_id⁺ = {user_id}\\ |
75 | | \\ |
76 | | **Company**\\ |
77 | | Суперклуч: id\\ |
78 | | id⁺ = {id, company_name, description, registration_number}\\ |
79 | | \\ |
80 | | Суперклуч: registration_number\\ |
81 | | registration_number⁺ = {registration_number, id, company_name, description}\\ |
82 | | \\ |
83 | | **Pharmacy**\\ |
84 | | Суперклуч: company_id\\ |
85 | | company_id⁺ = {company_id}\\ |
86 | | \\ |
87 | | **Distributor**\\ |
88 | | Суперклуч: company_id\\ |
89 | | company_id⁺ = {company_id}\\ |
90 | | \\ |
91 | | **Manufacturer**\\ |
92 | | Суперклуч: company_id\\ |
93 | | company_id⁺ = {company_id}\\ |
94 | | \\ |
95 | | **!DeliveryCompany**\\ |
96 | | Суперклуч: company_id\\ |
97 | | company_id⁺ = {company_id}\\ |
98 | | \\ |
99 | | **Facility**\\ |
100 | | Суперклуч: id\\ |
101 | | id⁺ = {id, company_id, facility_name, code}\\ |
102 | | \\ |
103 | | Суперклуч: code\\ |
104 | | code⁺ = {code, id, company_id, facility_name}\\ |
105 | | \\ |
106 | | **Inventory**\\ |
107 | | Суперклуч: id\\ |
108 | | id⁺ = {id, facility_id}\\ |
109 | | \\ |
110 | | Суперклуч: facility_id\\ |
111 | | facility_id⁺ = {facility_id, id}\\ |
112 | | \\ |
113 | | **Medicine**\\ |
114 | | Суперклуч: id\\ |
115 | | id⁺ = {id, medicine_name, active_ingredient}\\ |
116 | | \\ |
117 | | **!BrandedMedicine**\\ |
118 | | Суперклуч: id\\ |
119 | | id⁺ = {id, manufacturer_id, name, price, description, dosage_form, strength, origin_country}\\ |
120 | | \\ |
121 | | **!BrandedMedicineImage**\\ |
122 | | Суперклуч: id\\ |
123 | | id⁺ = {id, branded_medicine_id, image}\\ |
124 | | \\ |
125 | | **!ContactInformation**\\ |
126 | | Суперклуч: id\\ |
127 | | id⁺ = {id, phone, address, user_id, facility_id}\\ |
128 | | \\ |
129 | | **!ClubCard**\\ |
130 | | Суперклуч: id\\ |
131 | | id⁺ = {id, user_id, club_program, points}\\ |
132 | | \\ |
133 | | **!PaymentMethod**\\ |
134 | | Суперклуч: id\\ |
135 | | id⁺ = {id, method_name}\\ |
136 | | \\ |
137 | | **Payment**\\ |
138 | | Суперклуч: id\\ |
139 | | id⁺ = {id, client_id, payment_method_id, payment_date, amount, status}\\ |
140 | | \\ |
141 | | **!ClientOrder**\\ |
142 | | Суперклуч: id\\ |
143 | | id⁺ = {id, client_id, delivery_company_id, payment_id, order_date, expected_arrival_date, status, total_price}\\ |
144 | | \\ |
145 | | Суперклуч: payment_id\\ |
146 | | payment_id⁺ = {payment_id, id, client_id, delivery_company_id, order_date, expected_arrival_date, status, total_price}\\ |
147 | | \\ |
148 | | **!ShoppingCart**\\ |
149 | | Суперклуч: id\\ |
150 | | id⁺ = {id, client_id}\\ |
151 | | \\ |
152 | | **!SupplyOrder**\\ |
153 | | Суперклуч: id\\ |
154 | | id⁺ = {id, distributor_id, pharmacy_id, order_date, expected_arrival_date, status}\\ |
155 | | \\ |
156 | | **!HealthProfile**\\ |
157 | | Суперклуч: id\\ |
158 | | id⁺ = {id, client_id, blood_type}\\ |
159 | | \\ |
160 | | **!SensitiveClientData**\\ |
161 | | Суперклуч: id\\ |
162 | | id⁺ = {id, client_id, pharmacist_id, embg, portrait_photo, verification_status}\\ |
163 | | \\ |
164 | | **Prescription**\\ |
165 | | Суперклуч: id\\ |
166 | | id⁺ = {id, client_id, medicine_id, issued_by, issued_at, valid_to, embg}\\ |
167 | | \\ |
168 | | **ClientOrder_BrandedMedicine**\\ |
169 | | Суперклуч: {order_id, branded_medicine_id}\\ |
170 | | {order_id, branded_medicine_id}⁺ = {order_id, branded_medicine_id, quantity}\\ |
171 | | \\ |
172 | | **ShoppingCart_BrandedMedicine**\\ |
173 | | Суперклуч: {shopping_cart_id, branded_medicine_id}\\ |
174 | | {shopping_cart_id, branded_medicine_id}⁺ = {shopping_cart_id, branded_medicine_id, quantity}\\ |
175 | | \\ |
176 | | **SupplyOrder_BrandedMedicine**\\ |
177 | | Суперклуч: {supply_order_id, branded_medicine_id}\\ |
178 | | {supply_order_id, branded_medicine_id}⁺ = {supply_order_id, branded_medicine_id, quantity}\\ |
179 | | \\ |
180 | | **Inventory_BrandedMedicine**\\ |
181 | | Суперклуч: {inventory_id, branded_medicine_id}\\ |
182 | | {inventory_id, branded_medicine_id}⁺ = {inventory_id, branded_medicine_id, quantity, last_changed}\\ |
183 | | \\ |
184 | | **Pharmacy_Catalog**\\ |
185 | | Суперклуч: {pharmacy_id, branded_medicine_id}\\ |
186 | | {pharmacy_id, branded_medicine_id}⁺ = {pharmacy_id, branded_medicine_id}\\ |
187 | | \\ |
188 | | **Distributor_BrandedMedicine**\\ |
189 | | Суперклуч: {distributor_id, branded_medicine_id}\\ |
190 | | {distributor_id, branded_medicine_id}⁺ = {distributor_id, branded_medicine_id}\\ |
191 | | \\ |
192 | | **Branded_Medicine_InstanceOf_Medicine**\\ |
193 | | Суперклуч: {branded_medicine_id, medicine_id}\\ |
194 | | {branded_medicine_id, medicine_id}⁺ = {branded_medicine_id, medicine_id}\\ |
195 | | \\ |
196 | | **AllergicReaction_HealthProfile_Medicine**\\ |
197 | | Суперклуч: {health_profile_id, medicine_id}\\ |
198 | | {health_profile_id, medicine_id}⁺ = {health_profile_id, medicine_id, date_diagnosed, description, severity}\\ |
199 | | \\ |
200 | | **MedicineInteraction**\\ |
201 | | Суперклуч: {medicine_id_1, medicine_id_2}\\ |
202 | | {medicine_id_1, medicine_id_2}⁺ = {medicine_id_1, medicine_id_2, type, description, severity}\\ |
203 | | |
204 | | ---- |
205 | | |
206 | | == Проверка на BCNF |
207 | | |
208 | | **Users**\\ |
209 | | Табелата Users ги чува сите основни податоци за корисниците. Примарен клуч е id, но истовремено username и e_mail се декларирани како уникатни и затоа претставуваат алтернативни клучеви. Функционалните зависности се: id → {first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth}, како и username → id и e_mail → id. Бидејќи секоја зависност има клуч (или кандидат клуч) на левата страна, секој атрибут е целосно функционално зависен од клучот. \\ |
210 | | **Заклучок: Users е во BCNF.**\\ |
211 | | \\ |
212 | | **Client, Pharmacist, Admins**\\ |
213 | | Овие три релации се специјализации на Users и го користат user_id како примарен клуч. Во Client, атрибутот is_verified зависи единствено од user_id. Кај Pharmacist и Admins нема дополнителни атрибути освен врската со Users. Затоа, за сите три релации, левата страна на секоја функционална зависност е суперклуч. \\ |
214 | | **Заклучок: сите три релации се во BCNF.**\\ |
215 | | \\ |
216 | | **Company**\\ |
217 | | Релацијата Company има примарен клуч id, но и registration_number е уникатен и претставува алтернативен клуч. Зависностите се: id → {company_name, description, registration_number} и registration_number → id. И во двата случаи левата страна е клуч, што гарантира исполнување на BCNF. \\ |
218 | | **Заклучок: Company е во BCNF.**\\ |
219 | | \\ |
220 | | **Pharmacy, Distributor, Manufacturer, !DeliveryCompany**\\ |
221 | | Овие четири релации се специјализации на Company и го користат company_id како примарен клуч. Немаат сопствени не-клучни атрибути, па единствената зависност е company_id → {}. Како што секогаш левата страна е клуч, **сите се во BCNF.**\\ |
222 | | \\ |
223 | | **Facility**\\ |
224 | | Табелата Facility има два клуча: id и code (кој е уникатен). Зависностите се id → {company_id, facility_name, code} и code → id. Во двата случаи, левата страна е суперклуч, со што сите атрибути зависат целосно од клучевите. \\ |
225 | | **Заклучок: Facility е во BCNF.**\\ |
226 | | \\ |
227 | | **Inventory**\\ |
228 | | Релацијата Inventory има примарен клуч id и дополнително facility_id е уникатен, што создава уште еден алтернативен клуч. Зависностите се id → facility_id и facility_id → id. Ова е двонасочна зависност помеѓу два клуча. **Затоа релацијата е во BCNF.**\\ |
229 | | \\ |
230 | | **Medicine**\\ |
231 | | Релацијата Medicine има едноставен примарен клуч id. Функционалната зависност е id → {medicine_name, active_ingredient}. Нема дополнителни уникатни ограничувања, па сите атрибути зависат исклучиво од клучот. \\ |
232 | | **Заклучок: Medicine е во BCNF.**\\ |
233 | | \\ |
234 | | **!BrandedMedicine**\\ |
235 | | Оваа релација го користи id како примарен клуч и содржи повеќе атрибути (manufacturer_id, name, price, description, dosage_form, strength, origin_country). Функционалната зависност е id → {сите останати атрибути}. Производителот може да има повеќе лекови, па manufacturer_id сам по себе не е клуч. Левата страна (id) е клуч, така што **!BrandedMedicine е во BCNF.**\\ |
236 | | \\ |
237 | | **!BrandedMedicineImage**\\ |
238 | | Тука примарен клуч е id. Зависноста е id → {branded_medicine_id, image}. Бидејќи секој атрибут зависи од примарниот клуч, **релацијата е во BCNF.**\\ |
239 | | \\ |
240 | | **!ContactInformation**\\ |
241 | | Примарен клуч е id. Дополнителното ограничување бара секоја контакт информација да се однесува на точно еден објект или точно еден корисник. Зависностите се id → {phone, address, user_id, facility_id}. Сите зависности се со клуч на левата страна, па **!ContactInformation е во BCNF.**\\ |
242 | | \\ |
243 | | **!ClubCard**\\ |
244 | | Оваа релација има примарен клуч id. Сите останати атрибути (user_id, club_program, points) зависат единствено од овој клуч. Нема транзитивни зависности. Заклучок: **!ClubCard е во BCNF.**\\ |
245 | | \\ |
246 | | **!PaymentMethod**\\ |
247 | | Со примарен клуч id, единствената зависност е id → method_name. **Затоа релацијата е во BCNF.**\\ |
248 | | \\ |
249 | | **Payment**\\ |
250 | | Релацијата Payment има примарен клуч id. Атрибутите client_id, payment_method_id, payment_date, amount, status зависат директно од id. Нема други уникатни ограничувања што би создале транзитивни зависности. \\ |
251 | | **Заклучок: Payment е во BCNF.**\\ |
252 | | \\ |
253 | | **!ClientOrder**\\ |
254 | | Оваа релација има два кандидат клуча: id (PK) и payment_id (unique). Зависностите се id → {client_id, delivery_company_id, payment_id, order_date, expected_arrival_date, status, total_price} и payment_id → id. Бидејќи во двата случаи левата страна е клуч, **релацијата е во BCNF.**\\ |
255 | | \\ |
256 | | **!ShoppingCart**\\ |
257 | | Примарен клуч е id. Единствената зависност е id → {client_id}. Бидејќи левата страна е клуч, **релацијата е во BCNF.**\\ |
258 | | \\ |
259 | | **!SupplyOrder**\\ |
260 | | Примарен клуч е id. Сите останати атрибути (distributor_id, pharmacy_id, order_date, expected_arrival_date, status) зависат од овој клуч. \\ |
261 | | **Заклучок: !SupplyOrder е во BCNF.**\\ |
262 | | \\ |
263 | | **!HealthProfile**\\ |
264 | | Со примарен клуч id, останатите атрибути (client_id, blood_type) зависат исклучиво од клучот. \\ |
265 | | **Заклучок: !HealthProfile е во BCNF.**\\ |
266 | | \\ |
267 | | **!SensitiveClientData**\\ |
268 | | Примарен клуч е id. Сите останати атрибути (client_id, pharmacist_id, embg, portrait_photo, verification_status) зависат од него. \\ |
269 | | **Затоа релацијата е во BCNF.**\\ |
270 | | \\ |
271 | | **Prescription**\\ |
272 | | Примарен клуч е id. Функционалната зависност е id → {client_id, medicine_id, issued_by, issued_at, valid_to, embg}. Иако embg може да се повторува за повеќе рецепти, примарниот клуч секогаш е id, што гарантира BCNF. \\ |
273 | | **Заклучок: Prescription е во BCNF.**\\ |
274 | | \\ |
275 | | **ClientOrder_BrandedMedicine**\\ |
276 | | Оваа релација ги поврзува клиентските нарачки со брендираните лекови и содржи и атрибут quantity. Примарен клуч е составен: {order_id, branded_medicine_id}. Функционалната зависност е {order_id, branded_medicine_id} → {quantity}. Покривачот (order_id, branded_medicine_id)⁺ = {order_id, branded_medicine_id, quantity}, што ги содржи сите атрибути на релацијата. \\ |
277 | | **Затоа ClientOrder_BrandedMedicine е во BCNF.**\\ |
278 | | \\ |
279 | | **ShoppingCart_BrandedMedicine**\\ |
280 | | Оваа релација ги поврзува кошничките со брендираните лекови и содржи количество. Примарен клуч е {shopping_cart_id, branded_medicine_id}. Функционалната зависност е {shopping_cart_id, branded_medicine_id} → {quantity}. Покривачот на составниот клуч ги опфаќа сите атрибути, па нема парцијални ниту транзитивни зависности. **Заклучок: ShoppingCart_BrandedMedicine е во BCNF.**\\ |
281 | | \\ |
282 | | **SupplyOrder_BrandedMedicine**\\ |
283 | | Оваа релација поврзува нарачки за снабдување со брендирани лекови и содржи quantity. Примарен клуч е {supply_order_id, branded_medicine_id}. Зависност: {supply_order_id, branded_medicine_id} → {quantity}. Покривачот на составниот клуч ги содржи сите атрибути. \\ |
284 | | **Заклучок: SupplyOrder_BrandedMedicine е во BCNF.**\\ |
285 | | \\ |
286 | | **Inventory_BrandedMedicine**\\ |
287 | | Оваа релација поврзува магацини со брендирани лекови и содржи {quantity, last_changed}. Примарен клуч е {inventory_id, branded_medicine_id}. Зависностите се {inventory_id, branded_medicine_id} → {quantity, last_changed}. Покривачот на составниот клуч ги содржи сите атрибути, што значи дека **е во BCNF.**\\ |
288 | | \\ |
289 | | **Pharmacy_Catalog**\\ |
290 | | Релацијата ги поврзува аптеките со брендирани лекови. Примарен клуч е {pharmacy_id, branded_medicine_id}. Единствената зависност е составниот клуч → {} (нема дополнителни атрибути). Покривачот на клучот ги содржи сите атрибути, па **Pharmacy_Catalog е во BCNF.**\\ |
291 | | \\ |
292 | | **Distributor_BrandedMedicine**\\ |
293 | | Оваа релација поврзува дистрибутери со брендирани лекови. Примарен клуч е {distributor_id, branded_medicine_id}. Нема дополнителни атрибути, па функционалната зависност е {distributor_id, branded_medicine_id} → {}. Бидејќи клучот ги покрива сите атрибути, **Distributor_BrandedMedicine е во BCNF.**\\ |
294 | | \\ |
295 | | **Branded_Medicine_InstanceOf_Medicine**\\ |
296 | | Оваа релација ја врзува врската помеѓу брендирани и генерички лекови. Примарен клуч е {branded_medicine_id, medicine_id}. Зависноста е составниот клуч → {}. Покривачот на клучот ги содржи сите атрибути. \\ |
297 | | **Заклучок: Branded_Medicine_InstanceOf_Medicine е во BCNF.**\\ |
298 | | \\ |
299 | | **AllergicReaction_HealthProfile_Medicine**\\ |
300 | | Оваа релација ги поврзува здравствените профили со лекови што предизвикуваат алергиски реакции, и содржи дополнителни атрибути {date_diagnosed, description, severity}. Примарен клуч е {health_profile_id, medicine_id}. Функционалната зависност е {health_profile_id, medicine_id} → {date_diagnosed, description, severity}. Покривачот на составниот клуч ги содржи сите атрибути. **Затоа AllergicReaction_HealthProfile_Medicine е во BCNF.**\\ |
301 | | \\ |
302 | | **!MedicineInteraction**\\ |
303 | | Оваа релација ги опишува интеракциите помеѓу парови лекови. Примарен клуч е {medicine_id_1, medicine_id_2}. Дополнителните атрибути се {type, description, severity}. Функционалната зависност е {medicine_id_1, medicine_id_2} → {type, description, severity}. Со оглед дека составниот клуч ги покрива сите атрибути, **!MedicineInteraction е во BCNF.**\\ |
304 | | |
305 | | == Проверка на нормализација по промени поради Безбедност (Spring Security) |
306 | | |
307 | | Во релацијата Users ги додадовме: isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled — флагови што кореспондираат со UserDetails во Spring Security и се користат при автентикација.\\ |
308 | | \\После промените имаме:\\ |
309 | | **Users**\\ |
310 | | Суперклуч: id\\ |
311 | | id⁺ = {id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled}\\ |
312 | | \\ |
313 | | Суперклуч: username\\ |
314 | | username⁺ = {username, id, first_name, last_name, hashed_password, e_mail, gender, date_created, date_of_birth, isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled}\\ |
315 | | \\ |
316 | | Суперклуч: e_mail\\ |
317 | | e_mail⁺ = {e_mail, id, first_name, last_name, username, hashed_password, gender, date_created, date_of_birth, isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled}\\ |
318 | | \\ |
319 | | Со додавањето на безбедносните атрибути, сите нетривијални функционални зависности и натаму имаат клуч/суперклуч на лева страна => **Users останува во BCNF.** |
| 1 | == Нормализација == |
| 2 | |
| 3 | Во нашата база ги имаме следните id: company_id, medicine_id, payment_method_id, user_id, facility_id, inventory_id, branded_medicine_id, branded_medicine_image_id, clubcard_id, contactinformation_id, healthprofile_id, supply_order_id, client_order_id, prescription_id, sensitiveclientdata_id, shopping_cart_id, payment_id, medicine_id_1, medicine_id_2. |
| 4 | |
| 5 | Следат функционалните зависимости (ФЗ) извлечени директно од дефинираните ентитети (левата страна е PK или композитен PK). За описните полиња кои имаат исто име во повеќе релации ќе ја ставиме името на релацијата или скратено име како превикс — на пример company_description, branded_description, mi_description, allergic_description... — ова е само за јасност во анализата; |
| 6 | |
| 7 | Исто така за user_id и client_id во заграда ќе ја пишуваме нивната улога за подобро следење на контекстот на релациите. |
| 8 | |
| 9 | |
| 10 | **company_id** -> company_name, company_description, registration_number |
| 11 | **medicine_id** -> medicine_name, medicine_active_ingredient |
| 12 | **payment_method_id** -> payment_method_name |
| 13 | **user_id** -> first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified |
| 14 | **facility_id** -> company_id, facility_name, facility_code |
| 15 | **inventory_id** -> facility_id |
| 16 | **medicine_id_1, medicine_id_2** -> mi_type, mi_description, mi_severity |
| 17 | **payment_id** -> user_id (улога: client), payment_method_id, payment_date, payment_amount, payment_status |
| 18 | **prescription_id** -> user_id (улога: client), medicine_id, issued_by, issued_at, valid_to, prescription_embg |
| 19 | **sensitiveclientdata_id** -> user_id (улога: client), user_id (улога: pharmacist), sensitive_embg, portrait_photo, verification_status |
| 20 | **shopping_cart_id** -> user_id (улога: client) |
| 21 | **supply_order_id** -> company_id (улога: distributor), company_id (улога: pharmacy), supply_order_date, supply_expected_arrival_date, supply_status, facility_id |
| 22 | **branded_medicine_id** -> company_id (улога: manufacturer), branded_name, branded_price, branded_description, dosage_form, strength, origin_country |
| 23 | **branded_medicine_image_id** -> branded_medicine_id, branded_image, is_main_image |
| 24 | **clubcard_id** -> user_id, club_program, points |
| 25 | **contactinformation_id** -> phone, contact_address, contact_user_id, contact_facility_id |
| 26 | **healthprofile_id** -> user_id (улога: client), blood_type |
| 27 | **inventory_id, branded_medicine_id** -> quantity, last_changed |
| 28 | **client_order_id** -> user_id (улога: client), company_id (улога: delivery), payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price |
| 29 | **client_order_id, branded_medicine_id** -> order_quantity |
| 30 | **company_id (улога: pharmacy), branded_medicine_id** -> / |
| 31 | **shopping_cart_id, branded_medicine_id** -> cart_quantity |
| 32 | **supply_order_id, branded_medicine_id** -> supply_quantity |
| 33 | **healthprofile_id, medicine_id** -> date_diagnosed, allergic_description, allergic_severity |
| 34 | **branded_medicine_id, medicine_id** -> / |
| 35 | **company_id (улога: distributor), branded_medicine_id** -> / |
| 36 | |
| 37 | **R** = { company_id, company_name, company_description, registration_number, medicine_id, medicine_name, medicine_active_ingredient, payment_method_id, payment_method_name, user_id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, facility_id, facility_name, facility_code, inventory_id, branded_medicine_id, branded_name, branded_price, branded_description, dosage_form, strength, origin_country, branded_medicine_image_id, branded_image, is_main_image, clubcard_id, club_program, points, contactinformation_id, phone, contact_address, contact_user_id, contact_facility_id, healthprofile_id, blood_type, quantity, last_changed, client_order_id, payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price, order_quantity, shopping_cart_id, cart_quantity, supply_order_id, supply_order_date, supply_expected_arrival_date, supply_status, supply_quantity, payment_date, payment_amount, payment_status, prescription_id, issued_by, issued_at, valid_to, prescription_embg, sensitiveclientdata_id, sensitive_embg, portrait_photo, verification_status, medicine_id_1, medicine_id_2, mi_type, mi_description, mi_severity, date_diagnosed, allergic_description, allergic_severity, company_role_notes…, user_role_notes… }. |
| 38 | |
| 39 | **Лево** |
| 40 | branded_medicine_image_id |
| 41 | client_order_id |
| 42 | clubcard_id |
| 43 | company_id |
| 44 | contactinformation_id |
| 45 | facility_id |
| 46 | healthprofile_id |
| 47 | inventory_id |
| 48 | medicine_id |
| 49 | medicine_id_1 |
| 50 | medicine_id_2 |
| 51 | payment_id |
| 52 | payment_method_id |
| 53 | prescription_id |
| 54 | sensitiveclientdata_id |
| 55 | shopping_cart_id |
| 56 | supply_order_id |
| 57 | branded_medicine_id |
| 58 | user_id |
| 59 | |
| 60 | **Лево и десно** |
| 61 | company_id |
| 62 | medicine_id |
| 63 | payment_method_id |
| 64 | user_id |
| 65 | facility_id |
| 66 | inventory_id |
| 67 | branded_medicine_id |
| 68 | payment_id |
| 69 | |
| 70 | **Десно** |
| 71 | company_name, company_description, registration_number, medicine_name, medicine_active_ingredient, payment_method_name, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified, facility_name, facility_code, branded_name, branded_price, branded_description, dosage_form, strength, origin_country, branded_image, is_main_image, club_program, points, phone, contact_address, contact_user_id, contact_facility_id, blood_type, quantity, last_changed, client_order_date, client_expected_arrival_date, client_order_status, total_price, order_quantity, cart_quantity, supply_order_date, supply_expected_arrival_date, supply_status, supply_quantity, payment_date, payment_amount, payment_status, issued_by, issued_at, valid_to, prescription_embg, sensitive_embg, portrait_photo, verification_status, mi_type, mi_description, mi_severity, date_diagnosed, allergic_description, allergic_severity. |
| 72 | |
| 73 | == Покривачи за атрибутите од „Лево“ == |
| 74 | |
| 75 | **branded_medicine_image_id+** = { branded_medicine_image_id, branded_medicine_id, branded_image, is_main_image, company_id, branded_name, branded_price, branded_description, dosage_form, strength, origin_country } - **Не ги содржи сите атрибути.** |
| 76 | **client_order_id+** = { client_order_id, user_id, company_id, payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price, payment_method_id, payment_amount, payment_date, payment_status, payment_method_name } - **Не ги содржи сите атрибути.** |
| 77 | **clubcard_id+** = { clubcard_id, user_id, club_program, points, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified } - **Не ги содржи сите атрибути.** |
| 78 | **company_id+** = { company_id, company_name, company_description, registration_number } - **Не ги содржи сите атрибути.** |
| 79 | **contactinformation_id+** = { contactinformation_id, phone, contact_address, facility_id, facility_name, facility_code, company_id, company_name, company_description, registration_number, user_id, first_name, last_name, username } - **Не ги содржи сите атрибути.** |
| 80 | **facility_id+** = { facility_id, company_id, facility_name, facility_code, company_name, company_description, registration_number } - **Не ги содржи сите атрибути.** |
| 81 | **healthprofile_id+** = { healthprofile_id, user_id, blood_type, user_id, first_name, last_name, username } - **Не ги содржи сите атрибути.** |
| 82 | **inventory_id+** = { inventory_id, facility_id, facility_name, facility_code, company_id, company_name, company_description, registration_number } - **Не ги содржи сите атрибути.** |
| 83 | **medicine_id+** = { medicine_id, medicine_name, medicine_active_ingredient } - **Не ги содржи сите атрибути.** |
| 84 | **medicine_id_1+** = { medicine_id_1 } - **Не ги содржи сите атрибути.** |
| 85 | **medicine_id_2+** = { medicine_id_2 } - **Не ги содржи сите атрибути.** |
| 86 | **payment_id+** = { payment_id, user_id (улога: client), payment_method_id, payment_date, payment_amount, payment_status, payment_method_name } - **Не ги содржи сите атрибути.** |
| 87 | **payment_method_id+** = { payment_method_id, payment_method_name } - **Не ги содржи сите атрибути.** |
| 88 | **prescription_id+** = { prescription_id, user_id, medicine_id, issued_by, issued_at, valid_to, prescription_embg, medicine_name, medicine_active_ingredient } - **Не ги содржи сите атрибути.** |
| 89 | **sensitiveclientdata_id+** = { sensitiveclientdata_id, sensitive_embg, portrait_photo, verification_status, user_id, first_name, last_name } - **Не ги содржи сите атрибути.** |
| 90 | **shopping_cart_id+** = { shopping_cart_id, user_id, first_name, last_name } - **Не ги содржи сите атрибути** |
| 91 | **supply_order_id+** = { supply_order_id, supply_order_date, supply_expected_arrival_date, supply_status, facility_id, facility_name, company_id, company_name } - **Не ги содржи сите атрибути.** |
| 92 | **branded_medicine_id+** = { branded_medicine_id, company_id, branded_name, branded_price, branded_description, dosage_form, strength, origin_country } - **Не ги содржи сите атрибути.** |
| 93 | **user_id+** = { user_id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified } - **Не ги содржи сите атрибути.** |
| 94 | |
| 95 | |
| 96 | |
| 97 | === Kомбинирање на покривачите со цел да стигнеме до сите атрибути === |
| 98 | { client_order_id }+ додава: user_id, company_id, payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price, payment_method_id, payment_amount, payment_date, payment_status, payment_method_name. - **Не ги содржи сите атрибути.** |
| 99 | |
| 100 | { client_order_id, branded_medicine_id }+ додава: order_quantity, branded_name, branded_price, branded_description, dosage_form, strength, company_id, origin_country. - **Не ги содржи сите атрибути.** |
| 101 | |
| 102 | { client_order_id, branded_medicine_id, supply_order_id }+ додава: supply_quantity, supply_order_date, supply_expected_arrival_date, supply_status, company_id, company_id, facility_id, facility_name, facility_code, company_name, company_description, registration_number. - **Не ги содржи сите атрибути.** |
| 103 | |
| 104 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id }+ додава: prescription_id, user_id, medicine_id, issued_by, issued_at, valid_to, prescription_embg, medicine_name, medicine_active_ingredient. - **Не ги содржи сите атрибути.** |
| 105 | |
| 106 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id }+ додава: sensitiveclientdata_id, user_id, user_id, sensitive_embg, portrait_photo, verification_status. - **Не ги содржи сите атрибути.** |
| 107 | |
| 108 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2 }+ додава: mi_type, mi_description, mi_severity. - **Не ги содржи сите атрибути.** |
| 109 | |
| 110 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2, contactinformation_id }+ додава: contactinformation_id, phone, contact_address, contact_user_id, contact_facility_id, facility_id, facility_name, facility_code, company_id, company_name, company_description, registration_number. - **Не ги содржи сите атрибути.** |
| 111 | |
| 112 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2, contactinformation_id, healthprofile_id, medicine_id }+ додава: date_diagnosed, allergic_description, allergic_severity. - **Не ги содржи сите атрибути.** |
| 113 | |
| 114 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2, contactinformation_id, healthprofile_id, medicine_id, branded_medicine_image_id }+ додава: branded_medicine_image_id, branded_image, is_main_image, branded_name, branded_price, branded_description, dosage_form, strength, company_id, origin_country. - **Не ги содржи сите атрибути.** |
| 115 | |
| 116 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2, contactinformation_id, healthprofile_id, medicine_id, branded_medicine_image_id, inventory_id }+ додава: quantity, last_changed, inventory_id, facility_id, facility_name, facility_code, company_id, company_name, company_description, registration_number. - **Не ги содржи сите атрибути.** |
| 117 | |
| 118 | { client_order_id, branded_medicine_id, supply_order_id, prescription_id, sensitiveclientdata_id, medicine_id_1, medicine_id_2, contactinformation_id, healthprofile_id, medicine_id, branded_medicine_image_id, inventory_id, shopping_cart_id }+ додава: cart_quantity, shopping_cart_id, user_id. — **Со оваа комбинација унијата ги покрива сите атрибути на R.** |
| 119 | |
| 120 | Со оваа последна комбинација добивме унија која ја покрива целата шема R. Задоволена е 1НФ. Меѓутоа, не е задоволена 2НФ поради постоење на парцијални зависимости — некои примери се: |
| 121 | quantity, last_changed зависат од (inventory_id, branded_medicine_id) — делумна зависност ако останат во големата релација. |
| 122 | order_quantity зависи од (client_order_id, branded_medicine_id). |
| 123 | cart_quantity зависи од (shopping_cart_id, branded_medicine_id). |
| 124 | supply_quantity зависи од (supply_order_id, branded_medicine_id). |
| 125 | mi_type/mi_description/mi_severity зависат од (medicine_id_1, medicine_id_2). |
| 126 | |
| 127 | == Декомпозиција во 2НФ == |
| 128 | За да ги отстраниме парцијалните зависиности ги делиме атрибутите во релации каде не-клучните атрибути целосно зависат од нивниот клуч: |
| 129 | company_id → company_name, company_description, registration_number |
| 130 | medicine_id → medicine_name, medicine_active_ingredient |
| 131 | payment_method_id → payment_method_name |
| 132 | user_id → first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified (Client) |
| 133 | facility_id → company_id, facility_name, facility_code |
| 134 | inventory_id → facility_id |
| 135 | branded_medicine_id → company_id (улога: manufacturer), branded_name, branded_price, branded_description, dosage_form, strength, origin_country |
| 136 | branded_medicine_image_id → branded_medicine_id, branded_image, is_main_image |
| 137 | clubcard_id → user_id, club_program, points |
| 138 | contactinformation_id → phone, contact_address, contact_user_id, contact_facility_id |
| 139 | healthprofile_id → user_id (улога: client), blood_type |
| 140 | inventory_id, branded_medicine_id → quantity, last_changed |
| 141 | client_order_id → user_id (улога: client), company_id (улога: delivery), payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price |
| 142 | client_order_id, branded_medicine_id → order_quantity |
| 143 | shopping_cart_id → user_id (улога: client) |
| 144 | shopping_cart_id, branded_medicine_id → cart_quantity |
| 145 | supply_order_id → company_id (улога: distributor), company_id (улога: pharmacy), supply_order_date, supply_expected_arrival_date, supply_status, facility_id |
| 146 | supply_order_id, branded_medicine_id → supply_quantity |
| 147 | payment_id → user_id (улога: client), payment_method_id, payment_date, payment_amount, payment_status |
| 148 | prescription_id → user_id (улога: client), medicine_id, issued_by, issued_at, valid_to, prescription_embg |
| 149 | sensitiveclientdata_id → user_id (улога: client), user_id (улога: pharmacist), sensitive_embg, portrait_photo, verification_status |
| 150 | medicine_id_1, medicine_id_2 → mi_type, mi_description, mi_severity |
| 151 | healthprofile_id, medicine_id → date_diagnosed, allergic_description, allergic_severity |
| 152 | branded_medicine_id, medicine_id → (врска бранд->лек) |
| 153 | company_id (улога: distributor), branded_medicine_id → (junction) |
| 154 | company_id (улога: pharmacy), branded_medicine_id → (junction) |
| 155 | |
| 156 | Со ваква декомпозиција ги извлекуваме следните релации: |
| 157 | R1 { company_id, company_name, company_description, registration_number } - **во BCNF** |
| 158 | R2 { medicine_id, medicine_name, medicine_active_ingredient } - **во BCNF** |
| 159 | R3 { payment_method_id, payment_method_name } - **во BCNF** |
| 160 | R4 { user_id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified } - **во BCNF** |
| 161 | R5 { facility_id, company_id, facility_name, facility_code } - **во BCNF** |
| 162 | R6 { inventory_id, facility_id } - **во BCNF** |
| 163 | R7 { branded_medicine_id, company_id (улога: manufacturer), branded_name, branded_price, branded_description, dosage_form, strength, origin_country } - **во BCNF** |
| 164 | R8 { branded_medicine_image_id, branded_medicine_id, branded_image, is_main_image } - **во BCNF** |
| 165 | R9 { clubcard_id, user_id, club_program, points } - **во BCNF** |
| 166 | R10 { contactinformation_id, phone, contact_address, contact_user_id, contact_facility_id } - **во BCNF** |
| 167 | R11 { healthprofile_id, user_id (улога: client), blood_type } - **во BCNF** |
| 168 | R12 { inventory_id, branded_medicine_id, quantity, last_changed } - **во BCNF** |
| 169 | R13 { client_order_id, user_id (улога: client), company_id (улога: delivery), payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price } - **во BCNF** |
| 170 | R14 { client_order_id, branded_medicine_id, order_quantity } - **во BCNF** |
| 171 | R15 { shopping_cart_id, user_id (улога: client) } - **во BCNF** |
| 172 | R16 { shopping_cart_id, branded_medicine_id, cart_quantity } - **во BCNF** |
| 173 | R17 { supply_order_id, company_id (улога: distributor), company_id (улога: pharmacy), supply_order_date, supply_expected_arrival_date, supply_status, facility_id } - **во BCNF** |
| 174 | R18 { supply_order_id, branded_medicine_id, supply_quantity } - **во BCNF** |
| 175 | R19 { payment_id, user_id (улога: client), payment_method_id, payment_date, payment_amount, payment_status } - **во BCNF** |
| 176 | R20 { prescription_id, user_id (улога: client), medicine_id, issued_by, issued_at, valid_to, prescription_embg } - **во BCNF** |
| 177 | R21 { sensitiveclientdata_id, user_id (улога: client), user_id (улога: pharmacist), sensitive_embg, portrait_photo, verification_status } - **во BCNF** |
| 178 | R22 { medicine_id_1, medicine_id_2, mi_type, mi_description, mi_severity } - **во BCNF** |
| 179 | R23 { healthprofile_id, medicine_id, date_diagnosed, allergic_description, allergic_severity } - **во BCNF** |
| 180 | R24 { branded_medicine_id, medicine_id } (Branded_Medicine_InstanceOf_Medicine) - **во BCNF** |
| 181 | R25 { company_id (улога: distributor), branded_medicine_id } (Distributor_BrandedMedicine) - **во BCNF** |
| 182 | R26 { company_id (улога: pharmacy), branded_medicine_id } (Pharmacy_Catalog) - **во BCNF** |
| 183 | |
| 184 | |
| 185 | Проверка на 3НФ (транзитивни зависиности) и финална декомпозиција. |
| 186 | Сега ги проверуваме R1..R26 за транзитивни зависиности. Ако некаде постои транзитивност, ќе го декомпонираме дополнително. |
| 187 | Проверка на најважните случаи: |
| 188 | R7 (branded_medicine_id -> company_id (улога: manufacturer), …) — company_id е FK кон Company; Company е одвоена во R1, па нема транзитивна зависност во R7. R7 е во BCNF. |
| 189 | R5 (facility_id -> company_id, …) — company_… се во R1; нема транзитивност во R5. |
| 190 | R19 (payment_id -> payment_method_id, …) и R3 (payment_method_id -> payment_method_name) — се одделени: посебна релација за PaymentMethod (R3), а Payment држи само FK payment_method_id. Нема транзитивност во R19. |
| 191 | R12 (inventory_id, branded_medicine_id -> quantity, …) и R6 (inventory_id -> facility_id) — R6 и R12 се одделни; нема транзитивност во R12. |
| 192 | По проверка на секоја релација R1..R26 утврдуваме дека ниедна од нив не содржи внатрешни транзитивни зависиности (сите транзитивни детерминанти се извлечени во посебни релации: Company, PaymentMethod, Users, Facility, BrandedMedicine итн.). Следствено, R1..R26 се во 3НФ и BCNF. |
| 193 | |
| 194 | == Финални релации во BCNF == |
| 195 | **Company** { company_id, company_name, company_description, registration_number } - **BCNF** |
| 196 | **Medicine** { medicine_id, medicine_name, medicine_active_ingredient } - **BCNF** |
| 197 | **PaymentMethod** { payment_method_id, payment_method_name } - **BCNF** |
| 198 | **Users** { user_id, first_name, last_name, username, hashed_password, e_mail, gender, date_created, date_of_birth, is_account_non_expired, is_account_non_locked, is_credentials_non_expired, is_enabled, is_verified } - **BCNF** |
| 199 | **Facility** { facility_id, company_id, facility_name, facility_code } - **BCNF** |
| 200 | **Inventory** { inventory_id, facility_id } - **BCNF** |
| 201 | **BrandedMedicine** { branded_medicine_id, company_id (улога: manufacturer), branded_name, branded_price, branded_description, dosage_form, strength, origin_country } - **BCNF** |
| 202 | **BrandedMedicineImage** { branded_medicine_image_id, branded_medicine_id, branded_image, is_main_image } - **BCNF** |
| 203 | **ClubCard** { clubcard_id, user_id, club_program, points } - **BCNF** |
| 204 | **ContactInformation** { contactinformation_id, phone, contact_address, contact_user_id, contact_facility_id } - **BCNF** |
| 205 | **HealthProfile** { healthprofile_id, user_id (улога: client), blood_type } - **BCNF** |
| 206 | **Inventory_BrandedMedicine** { inventory_id, branded_medicine_id, quantity, last_changed } - **BCNF** |
| 207 | **ShoppingCart** { shopping_cart_id, user_id (улога: client) } - **BCNF** |
| 208 | **ShoppingCart_BrandedMedicine** { shopping_cart_id, branded_medicine_id, cart_quantity } - **BCNF** |
| 209 | **ClientOrder** { client_order_id, user_id (улога: client), company_id (улога: delivery), payment_id, client_order_date, client_expected_arrival_date, client_order_status, total_price } - **BCNF** |
| 210 | **ClientOrder_BrandedMedicine** { client_order_id, branded_medicine_id, order_quantity } - **BCNF** |
| 211 | **Payment** { payment_id, user_id (улога: client), payment_method_id, payment_date, payment_amount, payment_status } - **BCNF** |
| 212 | **Prescription** { prescription_id, user_id (улога: client), medicine_id, issued_by, issued_at, valid_to, prescription_embg } - **BCNF** |
| 213 | **SensitiveClientData** { sensitiveclientdata_id, user_id (улога: client), user_id (улога: pharmacist), sensitive_embg, portrait_photo, verification_status } - **BCNF** |
| 214 | **SupplyOrder** { supply_order_id, company_id (улога: distributor), company_id (улога: pharmacy), supply_order_date, supply_expected_arrival_date, supply_status, facility_id } - **BCNF** |
| 215 | **SupplyOrder_BrandedMedicine** { supply_order_id, branded_medicine_id, supply_quantity } - **BCNF** |
| 216 | **Pharmacy_Catalog** { company_id (улога: pharmacy), branded_medicine_id } - **BCNF** |
| 217 | **Distributor_BrandedMedicine** { company_id (улога: distributor), branded_medicine_id } - **BCNF** |
| 218 | **Branded_Medicine_InstanceOf_Medicine** { branded_medicine_id, medicine_id } - **BCNF** |
| 219 | **MedicineInteraction** { medicine_id_1, medicine_id_2, mi_type, mi_description, mi_severity } - **BCNF** |
| 220 | **AllergicReaction_HealthProfile_Medicine** { healthprofile_id, medicine_id, date_diagnosed, allergic_description, allergic_severity } - **BCNF** |
| 221 | |
| 222 | Дополнителни релациите Company и Client ги поделив на подтипови кои ги рефернецираат id-то на нивните родители. Оваа поделба ја правиме за подобра контекстуализација, и овие ентитети (освен Client) не соддржат дополнителни аттрибути. Сите во BCNF: |
| 223 | |
| 224 | **Admins** { user_id } |
| 225 | **Pharmacist** { user_id } |
| 226 | **Client** { user_id, is_verified } |
| 227 | **DeliveryCompany** { company_id } |
| 228 | **Distributor** { company_id } |
| 229 | **Manufacturer** { company_id } |
| 230 | **Pharmacy** { company_id } |