Changes between Version 4 and Version 5 of Normalization
- Timestamp:
- 09/02/25 18:43:39 (14 hours ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Normalization
v4 v5 9 9 === Функционални зависности 10 10 11 ==== Users 11 '''Users''' 12 12 13 13 `user_id → user_name, user_surname, user_pass, user_salt, user_email, user_mobile, user_active, user_image, clazz_, user_role, city_id` 14 14 15 ==== Customer го проширува User 15 '''Customer го проширува User''' 16 16 17 17 `user_id → cust_EDB, cust_company_name, cust_adr, cust_representative_img (каде што clazz_ = 'customer')` 18 18 19 ==== Manager го проширува User 19 '''Manager го проширува User''' 20 20 21 21 `user_id → wh_id (каде што clazz_ = 'manager')` 22 22 23 ==== Driver го проширува User 23 '''Driver го проширува User''' 24 24 25 25 `user_id → veh_id (каде што clazz_ = 'driver')` 26 26 27 ==== City 27 '''City''' 28 28 29 29 `city_id → city_name, region_id` 30 30 31 ==== Region 31 '''Region''' 32 32 33 33 `region_id → region_name` 34 34 35 ==== Warehouse 35 '''Warehouse''' 36 36 37 37 `wh_id → wh_adr, city_id` 38 38 39 ==== Vehicle 39 '''Vehicle''' 40 40 41 41 `veh_id → veh_carry_weight, veh_service_interval, veh_kilometers, veh_last_service, veh_last_service_km, veh_plate, veh_vin, veh_reg_date, wh_id` 42 42 43 ==== Categories 43 '''Categories''' 44 44 45 45 `ctg_id → ctg_name` 46 46 47 ==== Manufacturer 47 '''Manufacturer''' 48 48 49 49 `man_id → man_name, man_adr, man_mobile, man_email` 50 50 51 ==== Article 51 '''Article''' 52 52 53 53 `art_id → art_name, art_image, art_weight, ctg_id, man_id` 54 54 55 ==== Price 55 '''Price''' 56 56 57 57 `price_id → price, price_eff_date, art_id` 58 58 59 ==== Pro forma 59 '''Pro forma''' 60 60 61 61 `pf_id → pf_deadline, pf_date_created, pf_status_id` 62 62 63 ==== Pro Forma Status 63 '''Pro Forma Status''' 64 64 65 65 `pf_status_id → pf_status_name, pf_status_desc` 66 66 67 ==== Delivery 67 '''Delivery''' 68 68 69 69 `del_id → del_date_created, del_date, del_start_km, del_end_km, del_start_time, del_end_time, d_status_id, veh_id` 70 70 71 ==== Delivery Status 71 '''Delivery Status''' 72 72 73 73 `d_status_id → d_status_name, d_status_desc` 74 74 75 ==== Order 75 '''Order''' 76 76 77 77 `ord_id → ord_date, ord_sum, ord_fulfillment_date, ord_comment, o_status_id, cust_id, del_id, pf_id` 78 78 79 ==== Delivery Status 79 '''Delivery Status''' 80 80 81 81 `o_status_id → o_status_name, o_status_desc` 82 82 83 ==== Article unit 83 '''Article unit''' 84 84 85 85 `unit_id → unit_expiration_date, unit_serial_number, unit_batch_number, unit_manufacture_date, unit_cost_price, wh_id, ord_id` 86 86 87 ==== Weekday 87 '''Weekday''' 88 88 89 89 `day_id → day_name` 90 90 91 ==== Customer weekday 91 '''Customer weekday''' 92 92 93 93 `cust_day_id → cust_id, day_id, start_time, end_time` 94 94 95 ==== Token 95 '''Token''' 96 96 97 97 `t_id → t_value, t_date, t_type, t_expiry, t_validated_at, t_user` 98 98 99 ==== Image store 99 '''Image store''' 100 100 101 101 `img_id → img_path, img_ent_type, img_ent_id` … … 117 117 === Покривачи на примарните клучеви 118 118 119 ==== Vehicle 119 '''Vehicle''' 120 120 121 121 `veh_id+ = {veh_id, veh_carry_weight, veh_service_interval, veh_kilometers, veh_last_service, veh_last_service_km, veh_plate, veh_vin, veh_reg_date, wh_id, wh_adr, city_id, city_name, region_id, region_name}` 122 122 123 ==== User 123 '''User''' 124 124 125 125 `user_id+ = {user_id, user_name, user_surname, user_pass, user_salt, user_email, user_mobile, user_active, user_image, clazz_, user_role, city_id, city_name, region_id, region_name}` … … 137 137 `user_id+ += {veh_id, veh_carry_weight, veh_service_interval, veh_kilometers, veh_last_service, veh_last_service_km, veh_plate, veh_vin, veh_reg_date, wh_id, wh_adr}` 138 138 139 ==== Manufacturer 139 '''Manufacturer''' 140 140 141 141 `man_id+ = {man_id, man_name, man_adr, man_mobile, man_email}` 142 142 143 ==== Article 143 '''Article''' 144 144 145 145 `art_id+ = {art_id, art_name, art_image, art_weight, ctg_id, ctg_name, man_id, man_name, man_adr, man_mobile, man_email}` 146 146 147 ==== Price 147 '''Price''' 148 148 149 149 `price_id+ = {price_id, price, price_eff_date, art_id, art_name, art_image, art_weight, ctg_id, ctg_name, man_id, man_name, man_adr, man_mobile, man_email}` 150 150 151 ==== Pro-forma 151 '''Pro-forma''' 152 152 153 153 `pf_id+ = {pf_id, pf_deadline, pf_date_created, pf_status_id, pf_status_name, pf_status_desc}` 154 154 155 ==== Delivery 155 '''Delivery''' 156 156 157 157 `del_id+ = {del_id, del_date_created, del_date, del_start_km, del_end_km, del_start_time, del_end_time, d_status_id, d_status_name, d_status_desc, veh_id, veh_carry_weight, veh_service_interval, veh_kilometers, veh_last_service, veh_last_service_km, veh_plate, veh_vin, veh_reg_date, wh_id, wh_adr, city_id, city_name, region_id, region_name}` 158 158 159 ==== Order 159 '''Order''' 160 160 161 161 `ord_id+ = {ord_id, ord_date, ord_sum, ord_fulfillment_date, ord_comment, o_status_id, o_status_name, o_status_desc, cust_id, del_id, pf_id, user_name, user_surname, user_pass, user_salt, user_email, user_mobile, user_active, user_image, clazz_, user_role, city_id, cust_EDB, cust_company_name, cust_adr, cust_representative_img, city_name, region_id, region_name, del_date_created, del_date, del_start_km, del_end_km, del_start_time, del_end_time, d_status_id, veh_id, d_status_name, d_status_desc, veh_carry_weight, veh_service_interval, veh_kilometers, veh_last_service, veh_last_service_km, veh_plate, veh_vin, veh_reg_date, wh_id, wh_adr,pf_deadline, pf_date_created, pf_status_id, pf_status_name, pf_status_desc}` 162 162 163 ==== Article Unit 163 '''Article Unit''' 164 164 165 165 `unit_id+ = {unit_id, unit_expiration_date, unit_serial_number, unit_batch_number, unit_manufacture_date, unit_cost_price, wh_id, wh_adr, city_id, city_name, region_id, region_name, ord_id}` … … 172 172 `}` 173 173 174 ==== Композитен клуч - Article Unit и Price 174 '''Композитен клуч - Article Unit и Price''' 175 175 176 176 `(unit_id, price_id)+ = {unit_id, price_id,` … … 188 188 `wh_adr, city_id, city_name, region_id, region_name, art_name, art_image, art_weight, ctg_id, man_id, ctg_name, man_name, man_adr, man_mobile, man_email}` 189 189 190 ==== Weekday 190 '''Weekday''' 191 191 192 192 `cust_day_id+ = {cust_day_id, cust_id, day_id, start_time, end_time,` … … 204 204 `city_name, region_id, region_name}` 205 205 206 ==== Token 206 '''Token''' 207 207 208 208 `t_id+ = {t_id, t_value, t_date, t_type, t_expiry, t_validated_at, t_user,` … … 216 216 `city_name, region_id, region_name}` 217 217 218 ==== Image Store 218 '''Image Store''' 219 219 220 220 `img_id+ = {img_id, img_path, img_ent_type, img_ent_id}` … … 229 229 * Поврзување на слики: `img_id → img_ent_type, img_ent_id` 230 230 231 == Проблеми и подобрување на дизајн 232 231 == Анализа на нормални форми 232 233 === 1 НФ 234 235 Овој дизајн ја задоволува првата нормативна форма со тоа што: 236 237 * Сите атрибути се атомични. 238 * Секоја табела има примарен клуч. 239 * Нема табела со колона која содржи повеќе вредности. 240 241 === 2 НФ 242 243 Овој дизајн ја задоволува втората нормативна форма со тоа што: 244 245 * Ја задоволува 1НФ. 246 * Сите обични атрибути се целосно зависни од 1 примарен клуч, секоја табела има 1 примарен клуч. 247 * Ниту една табела со композитен примарен клуч нема атрибути кои зависат само од еден дел на тој клуч - нема парцијални зависности. 248 249 === 3 НФ 250 251 Барања: 252 * Мора да ја задоволува 2 НФ. 253 * Да нема транзитивни зависности. 254 255 ==== Прекршоци на 3 НФ 256 * Сервисна историја на возила во ентитетот `Vehicle`. 257 * Деталите за сервис, конкретно атрибутите - `veh_last_service` и `veh_last_service_km` - зависат од настанот - сервис, а не директно од возилото. 258 * '''Функционална зависност''': `veh_id->veh_last_service->(service details)`. 259 * Проблем: Не може да се следат повеќе сервисни настани, се зачувува само последната. 260 * Article Unit Cost Price 261 * Цената на чинење на еден артикл зависи од временскиот период, не само од единката артикл. 262 * '''Функционална зависност''': `unit_id->unit_cost_price->(треба да зависи на временски период)` 263 * Проблем: Не може да се следат промени на цени. 264 265 ===== Подобрувања на дизајнот за да се задоволи 3 НФ 266 267 ====== Vehicle 268 269 * Креирање на нова табела за сервисна историја 270 271 {{{#!sql 272 create table vehicle_service { 273 service_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 274 veh_id INT NOT NULL, 275 service_date DATE NOT NULL, 276 service_km INT NOT NULL, 277 service_type VARCHAR(255) NOT NULL, 278 service_notes TEXT, 279 service_cost DECIMAL(10,2), 280 service_next_date DATE, 281 service_next_km INT, 282 FOREIGN KEY (veh_id) REFERENCES vehicle (veh_id) 283 } 284 }}} 285 286 * Бришење на атрибутите од `vehicle` 287 288 {{{#!sql 289 create table vehicle_service { 290 ALTER TABLE vehicle DROP COLUMN veh_last_service; 291 ALTER TABLE vehicle DROP COLUMN veh_last_service_km; 292 }}} 293 294 * Креирање на поглед за полесен пристап до информации за последен сервис 295 296 297 {{{#!sql 298 CREATE VIEW vehicle_latest_service AS 299 SELECT v.veh_id, 300 vs.service_date AS last_service_date, 301 vs.service_km AS last_service_km, 302 vs.service_next_date, 303 vs.service_next_km 304 FROM vehicle v 305 LEFT JOIN ( 306 SELECT veh_id, 307 service_date, 308 service_km, 309 service_next_date, 310 service_next_km, 311 ROW_NUMBER() OVER (PARTITION BY veh_id ORDER BY service_date DESC) as rn 312 FROM vehicle_service 313 ) vs ON v.veh_id = vs.veh_id AND vs.rn = 1; 314 }}} 315 316 ====== Article Unit 317 318 * Креирање на нова табела за историја на чинење за единка артикл 319 320 321 {{{#!sql 322 CREATE TABLE unit_cost_history ( 323 history_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 324 unit_id BIGINT NOT NULL, 325 cost_price DECIMAL(10,2) NOT NULL, 326 effective_date DATE NOT NULL DEFAULT CURRENT_DATE, 327 recorded_by BIGINT, 328 FOREIGN KEY (unit_id) REFERENCES article_unit (unit_id), 329 FOREIGN KEY (recorded_by) REFERENCES users (user_id) 330 ); 331 }}} 332 333 * Отстранување на на атрибутот `unit_cost_price` 334 335 336 {{{#!sql 337 ALTER TABLE article_unit DROP COLUMN unit_cost_price; 338 }}} 339 340 * Креирање на поглед за полесен пристап до моменталната цена на единка 341 342 343 {{{#!sql 344 CREATE VIEW article_unit_current_cost AS 345 SELECT au.unit_id, uch.cost_price 346 FROM article_unit au 347 LEFT JOIN ( 348 SELECT unit_id, 349 cost_price, 350 ROW_NUMBER() OVER (PARTITION BY unit_id ORDER BY effective_date DESC) as rn 351 FROM unit_cost_history 352 ) uch ON au.unit_id = uch.unit_id AND uch.rn = 1; 353 }}} 354 355 === BCNF 356 357 Барања: 358 * Мора да ја задоволува 3 НФ. 359 * За секоја нетривијална функционална зависност `X->Y`, мора да има супер-клуч (кандидат клуч) 360 361 ==== Прекршоци на BCNF 362 363 * Атрибутот `email` во ентитетот `Users` не е уникатен. 364 * Атрибутот `EDB` во ентитетот `Customer` не е уникатен. 365 * Референцирање на ентитети во `image_store` 366 * Моментално нема начин да се осигураме дека `img_ent_id` всушност референцира валиден ентитет. 367 368 ==== Подобрувања на дизајнот за да се задоволи BCNF 369 370 ===== Users 371 372 * Атрибутот `email` во ентитетот `Users` да добие ограничување да е уникатен. 373 374 {{{#!sql 375 alter table users add constraint uq_user_email unique(user_email) ; 376 }}} 377 378 ===== Customer 379 380 * Атрибутот `EDB` во ентитетот `Customer` да добие ограничување да е уникатен. 381 382 {{{#!sql 383 alter table customer add constraint uq_cust_edb unique(cust_EDB); 384 }}} 385 386 ===== Image store 387 388 * Ограничување на типот на валидни ентитети 389 390 {{{#!sql 391 alter table image_store 392 add constraint check_img_entity_type 393 check (img_ent_type in ('user', 'article', 'customer', 'vehicle')); 394 }}} 395 396 * Додавање на индекс за подобри перформанси при пребарување. 397 398 {{{#!sql 399 create index idx_img_entity on image_store(img_ent_type, img_ent_id); 400 }}} 401 402 * Збогатување на ентитетот со атрибути. 403 404 {{{#!sql 405 alter table image_store 406 add column img_title varchar(255), 407 add column img_upload_date timestamp default current_timestamp, 408 add column img_uploaded_by bigint, 409 add constraint fk_img_uploader foreign key (img_uploaded_by) references users(user_id); 410 }}} 411