Changes between Version 4 and Version 5 of Normalization


Ignore:
Timestamp:
09/02/25 18:43:39 (14 hours ago)
Author:
185022
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v4 v5  
    99=== Функционални зависности
    1010
    11 ==== Users
     11'''Users'''
    1212
    1313`user_id → user_name, user_surname, user_pass, user_salt, user_email, user_mobile, user_active, user_image, clazz_, user_role, city_id`
    1414
    15 ==== Customer го проширува User
     15'''Customer го проширува User'''
    1616
    1717`user_id → cust_EDB, cust_company_name, cust_adr, cust_representative_img  (каде што clazz_ = 'customer')`
    1818
    19 ==== Manager го проширува User
     19'''Manager го проширува User'''
    2020
    2121`user_id → wh_id  (каде што clazz_ = 'manager')`
    2222
    23 ==== Driver го проширува User
     23'''Driver го проширува User'''
    2424
    2525`user_id → veh_id  (каде што clazz_ = 'driver')`
    2626
    27 ==== City
     27'''City'''
    2828
    2929`city_id → city_name, region_id`
    3030
    31 ==== Region
     31'''Region'''
    3232
    3333`region_id → region_name`
    3434
    35 ==== Warehouse
     35'''Warehouse'''
    3636
    3737`wh_id → wh_adr, city_id`
    3838
    39 ==== Vehicle
     39'''Vehicle'''
    4040
    4141`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`
    4242
    43 ==== Categories
     43'''Categories'''
    4444
    4545`ctg_id → ctg_name`
    4646
    47 ==== Manufacturer
     47'''Manufacturer'''
    4848
    4949`man_id → man_name, man_adr, man_mobile, man_email`
    5050
    51 ==== Article
     51'''Article'''
    5252
    5353`art_id → art_name, art_image, art_weight, ctg_id, man_id`
    5454
    55 ==== Price
     55'''Price'''
    5656
    5757`price_id → price, price_eff_date, art_id`
    5858
    59 ==== Pro forma
     59'''Pro forma'''
    6060
    6161`pf_id → pf_deadline, pf_date_created, pf_status_id`
    6262
    63 ==== Pro Forma Status
     63'''Pro Forma Status'''
    6464
    6565`pf_status_id → pf_status_name, pf_status_desc`
    6666
    67 ==== Delivery
     67'''Delivery'''
    6868
    6969`del_id → del_date_created, del_date, del_start_km, del_end_km, del_start_time, del_end_time, d_status_id, veh_id`
    7070
    71 ==== Delivery Status
     71'''Delivery Status'''
    7272
    7373`d_status_id → d_status_name, d_status_desc`
    7474
    75 ==== Order
     75'''Order'''
    7676
    7777`ord_id → ord_date, ord_sum, ord_fulfillment_date, ord_comment, o_status_id, cust_id, del_id, pf_id`
    7878
    79 ==== Delivery Status
     79'''Delivery Status'''
    8080
    8181`o_status_id → o_status_name, o_status_desc`
    8282
    83 ==== Article unit
     83'''Article unit'''
    8484
    8585`unit_id → unit_expiration_date, unit_serial_number, unit_batch_number, unit_manufacture_date, unit_cost_price, wh_id, ord_id`
    8686
    87 ==== Weekday
     87'''Weekday'''
    8888
    8989`day_id → day_name`
    9090
    91 ==== Customer weekday
     91'''Customer weekday'''
    9292
    9393`cust_day_id → cust_id, day_id, start_time, end_time`
    9494
    95 ==== Token
     95'''Token'''
    9696
    9797`t_id → t_value, t_date, t_type, t_expiry, t_validated_at, t_user`
    9898
    99 ==== Image store
     99'''Image store'''
    100100
    101101`img_id → img_path, img_ent_type, img_ent_id`
     
    117117=== Покривачи на примарните клучеви
    118118
    119 ==== Vehicle
     119'''Vehicle'''
    120120
    121121`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}`
    122122
    123 ==== User
     123'''User'''
    124124
    125125`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}`
     
    137137`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}`
    138138
    139 ==== Manufacturer
     139'''Manufacturer'''
    140140
    141141`man_id+ = {man_id, man_name, man_adr, man_mobile, man_email}`
    142142
    143 ==== Article
     143'''Article'''
    144144
    145145`art_id+ = {art_id, art_name, art_image, art_weight, ctg_id, ctg_name, man_id, man_name, man_adr, man_mobile, man_email}`
    146146
    147 ==== Price
     147'''Price'''
    148148
    149149`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}`
    150150
    151 ==== Pro-forma
     151'''Pro-forma'''
    152152
    153153`pf_id+ = {pf_id, pf_deadline, pf_date_created, pf_status_id, pf_status_name, pf_status_desc}`
    154154
    155 ==== Delivery
     155'''Delivery'''
    156156
    157157`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}`
    158158
    159 ==== Order
     159'''Order'''
    160160
    161161`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}`
    162162
    163 ==== Article Unit
     163'''Article Unit'''
    164164
    165165`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}`
     
    172172`}`
    173173
    174 ==== Композитен клуч - Article Unit и Price
     174'''Композитен клуч - Article Unit и Price'''
    175175
    176176`(unit_id, price_id)+ = {unit_id, price_id,`
     
    188188`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}`
    189189
    190 ==== Weekday
     190'''Weekday'''
    191191
    192192`cust_day_id+ = {cust_day_id, cust_id, day_id, start_time, end_time,`
     
    204204`city_name, region_id, region_name}`
    205205
    206 ==== Token
     206'''Token'''
    207207
    208208`t_id+ = {t_id, t_value, t_date, t_type, t_expiry, t_validated_at, t_user,`
     
    216216`city_name, region_id, region_name}`
    217217
    218 ==== Image Store
     218'''Image Store'''
    219219
    220220`img_id+ = {img_id, img_path, img_ent_type, img_ent_id}`
     
    229229* Поврзување на слики: `img_id → img_ent_type, img_ent_id`
    230230
    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
     272create 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
     289create table vehicle_service {
     290ALTER TABLE vehicle DROP COLUMN veh_last_service;
     291ALTER TABLE vehicle DROP COLUMN veh_last_service_km;
     292}}}
     293
     294* Креирање на поглед за полесен пристап до информации за последен сервис
     295
     296
     297{{{#!sql
     298CREATE VIEW vehicle_latest_service AS
     299SELECT 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
     304FROM vehicle v
     305LEFT 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
     322CREATE 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
     337ALTER TABLE article_unit DROP COLUMN unit_cost_price;
     338}}}
     339
     340* Креирање на поглед за полесен пристап до моменталната цена на единка
     341
     342
     343{{{#!sql
     344CREATE VIEW article_unit_current_cost AS
     345SELECT au.unit_id, uch.cost_price
     346FROM article_unit au
     347LEFT 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
     375alter table users add constraint uq_user_email unique(user_email) ;
     376}}}
     377
     378===== Customer
     379 
     380* Атрибутот `EDB` во ентитетот `Customer` да добие ограничување да е уникатен.
     381
     382{{{#!sql
     383alter table customer add constraint uq_cust_edb unique(cust_EDB);
     384}}}
     385
     386===== Image store
     387
     388* Ограничување на типот на валидни ентитети
     389
     390{{{#!sql
     391alter table image_store
     392add constraint check_img_entity_type
     393check (img_ent_type in ('user', 'article', 'customer', 'vehicle'));
     394}}}
     395
     396* Додавање на индекс за подобри перформанси при пребарување.
     397
     398{{{#!sql
     399create index idx_img_entity on image_store(img_ent_type, img_ent_id);
     400}}}
     401
     402* Збогатување на ентитетот со атрибути.
     403
     404{{{#!sql
     405alter table image_store
     406add column img_title varchar(255),
     407add column img_upload_date timestamp default current_timestamp,
     408add column img_uploaded_by bigint,
     409add constraint fk_img_uploader foreign key (img_uploaded_by) references users(user_id);
     410}}}
     411