wiki:Normalization

Version 10 (modified by 221181, 12 days ago) ( diff )

--

Формална анализа и доказ за нормализација на Stock Master

1. Дефиниција на универзалната релација

Тргнуваме од една единствена универзална релација која ги содржи сите атрибути од доменот. Заборавме на ентитети и релации - имаме само една релација со сите податоци:

Нека R претставува универзалната шема на релацијата. Множеството на атрибути U во R е дефинирано како:

U(userId, user_username, user_password, user_full_name, user_email, user_role, user_is_active,
  customerId, customer_name, customer_email, customer_phone, customer_address,
  productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level,
  categoryId, category_name, category_description,
  supplierId, supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address,
  warehouseId, warehouse_name, warehouse_location, warehouse_capacity,
  saleId, sale_date_time, sale_total_amount,
  poId, po_order_date, po_expected_delivery_date, po_status,
  saleitem_quantity, saleitem_unit_price_at_sale,
  poitem_quantity, poitem_unit_cost,
  stock_quantity_on_hand, stock_last_updated)

2. Функционални зависности

Ги идентификуваме сите функционални зависности што важат во универзалната релација:

F = {

  • FD1: userId → user_username, user_password, user_full_name, user_email, user_role, user_is_active
  • FD2: user_username → userId, user_password, user_full_name, user_email, user_role, user_is_active
  • FD3: user_email → userId, user_username, user_password, user_full_name, user_role, user_is_active
  • FD4: customerId → customer_name, customer_email, customer_phone, customer_address
  • FD5: productId → product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId
  • FD6: product_sku → productId, product_name, product_description, product_unit_price, product_reorder_level, categoryId, supplierId
  • FD7: categoryId → category_name, category_description
  • FD8: supplierId → supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address
  • FD9: warehouseId → warehouse_name, warehouse_location, warehouse_capacity
  • FD10: saleId → sale_date_time, sale_total_amount, userId, customerId, warehouseId
  • FD11: poId → po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId
  • FD12: {saleId, productId} → saleitem_quantity, saleitem_unit_price_at_sale
  • FD13: {poId, productId} → poitem_quantity, poitem_unit_cost
  • FD14: {warehouseId, productId} → stock_quantity_on_hand, stock_last_updated

}


3. Кандидат клучеви и примарен клуч

3.1 Определување на кандидат клучеви

За да најдеме кандидат клуч, треба да најдеме минимално множество атрибути чиј затворач ги содржи сите атрибути на релацијата.

3.2 Класификација на атрибути (Лева/Десна страна)

Атрибут Лева страна Десна страна Класификација
userId ✓ (FD1,FD3) ✓ (FD2,FD3,FD10) Обете
user_username ✓ (FD2) ✓ (FD1,FD3) Обете
user_email ✓ (FD3) ✓ (FD1,FD2) Обете
user_password Само десно
user_full_name Само десно
user_role Само десно
user_is_active Само десно
customerId ✓ (FD4) ✓ (FD10) Обете
customer_name Само десно
customer_email Само десно
customer_phone Само десно
customer_address Само десно
productId ✓ (FD5,FD12,FD13,FD14) ✓ (FD6) Обете
product_sku ✓ (FD6) ✓ (FD5) Обете
product_name Само десно
product_description Само десно
product_unit_price Само десно
product_reorder_level Само десно
categoryId ✓ (FD7) ✓ (FD5,FD6) Обете
category_name Само десно
category_description Само десно
supplierId ✓ (FD8) ✓ (FD5,FD6,FD11) Обете
supplier_name Само десно
supplier_contact_person Само десно
supplier_phone Само десно
supplier_email Само десно
supplier_address Само десно
warehouseId ✓ (FD9,FD14) ✓ (FD10,FD11) Обете
warehouse_name Само десно
warehouse_location Само десно
warehouse_capacity Само десно
saleId ✓ (FD10,FD12) Само лево
sale_date_time Само десно
sale_total_amount Само десно
poId ✓ (FD11,FD13) Само лево
po_order_date Само десно
po_expected_delivery_date Само десно
po_status Само десно
saleitem_quantity Само десно
saleitem_unit_price_at_sale Само десно
poitem_quantity Само десно
poitem_unit_cost Само десно
stock_quantity_on_hand Само десно
stock_last_updated Само десно

3.3 Атрибути кои се појавуваат САМО на лева страна

  • saleId - мора да биде дел од секој кандидат клуч
  • poId - мора да биде дел од секој кандидат клуч

3.4 Пресметка на затворач

Чекор 1: Започнуваме со {saleId, poId} и пресметуваме затворач:

{saleId, poId}⁺:
- Од FD10 (saleId →): добиваме sale_date_time, sale_total_amount, userId, customerId, warehouseId
- Од FD11 (poId →): добиваме po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId
- Од FD1 (userId →): добиваме user_username, user_password, user_full_name, user_email, user_role, user_is_active
- Од FD4 (customerId →): добиваме customer_name, customer_email, customer_phone, customer_address
- Од FD8 (supplierId →): добиваме supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address
- Од FD9 (warehouseId →): добиваме warehouse_name, warehouse_location, warehouse_capacity

{saleId, poId}⁺ ≠ U

Недостасуваат: productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, category_name, category_description, saleitem_quantity, saleitem_unit_price_at_sale, poitem_quantity, poitem_unit_cost, stock_quantity_on_hand, stock_last_updated

Чекор 2: Додаваме productId:

{saleId, poId, productId}⁺:
- Сè од претходно, плус:
- Од FD5 (productId →): добиваме product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId
- Од FD7 (categoryId →): добиваме category_name, category_description
- Од FD12 ({saleId, productId} →): добиваме saleitem_quantity, saleitem_unit_price_at_sale
- Од FD13 ({poId, productId} →): добиваме poitem_quantity, poitem_unit_cost
- Од FD14 ({warehouseId, productId} →): добиваме stock_quantity_on_hand, stock_last_updated

{saleId, poId, productId}⁺ = U (ги содржи сите атрибути) ✓

3.5 Проверка за минималност

Подмножество Затворач = U?
{saleId, poId}⁺ Недостасуваат атрибути поврзани со productId ✗ НЕ
{saleId, productId}⁺ Недостасуваат атрибути од poId: po_order_date, po_expected_delivery_date, po_status, poitem_quantity, poitem_unit_cost ✗ НЕ
{poId, productId}⁺ Недостасуваат атрибути од saleId: sale_date_time, sale_total_amount, saleitem_quantity, saleitem_unit_price_at_sale, userId→атрибути, customerId→атрибути ✗ НЕ

Заклучок: {saleId, poId, productId} е минимален и е кандидат клуч.

3.6 Други кандидат клучеви

Бидејќи постојат еквиваленции (FD5 и FD6 покажуваат дека productId ↔ product_sku), можеме да го замениме productId со product_sku:

Кандидат клуч 2: {saleId, poId, product_sku}

Проверка: {saleId, poId, product_sku}⁺:
- Од FD6 (product_sku →): добиваме productId и сите атрибути на продукт
- Понатаму идентично како горе

{saleId, poId, product_sku}⁺ = U ✓

3.7 Избор на примарен клуч

Кандидат клуч Број на атрибути Тип на атрибути
{saleId, poId, productId} 3 Сурогат клучеви (стабилни)
{saleId, poId, product_sku} 3 Мешано (saleId, poId сурогат; sku природен)

Избран примарен клуч: {saleId, poId, productId}

Образложение:

  1. Сите три атрибути се сурогат клучеви кои не се менуваат со тек на време
  2. productId е понумерички и поефикасен за индексирање од product_sku (кој е VARCHAR)
  3. Сурогат клучевите обезбедуваат стабилност - ако се промени SKU кодот на продукт, примарниот клуч останува непроменет

4. 1NF Декомпозиција

4.1 Проверка за 1NF

Универзалната релација U е во 1NF бидејќи:

  • Сите атрибути се атомски (нема повеќевредносни атрибути)
  • Постои примарен клуч: {saleId, poId, productId}
  • Нема повторувачки групи

Заклучок: U е во 1NF. ✓

4.2 Проверка која FD ја нарушува 2NF

За да биде во 2NF, секој не-клучен атрибут мора целосно да зависи од примарниот клуч (нема парцијални зависности).

Примарен клуч: {saleId, poId, productId}

Парцијални зависности (атрибути кои зависат од дел од клучот):

FD Детерминант Дел од клуч? Парцијална зависност?
FD1: userId → user_* userId НЕ (транзитивно преку saleId) Не директно
FD5: productId → product_*, categoryId, supplierId productId ДА (productId е дел од клучот) ДА
FD10: saleId → sale_*, userId, customerId, warehouseId saleId ДА (saleId е дел од клучот) ДА
FD11: poId → po_*, supplierId, warehouseId poId ДА (poId е дел од клучот) ДА
FD12: {saleId, productId} → saleitem_* {saleId, productId} ДА (подмножество на клучот) ДА
FD13: {poId, productId} → poitem_* {poId, productId} ДА (подмножество на клучот) ДА
FD14: {warehouseId, productId} → stock_* {warehouseId, productId} warehouseId не е во клучот директно Посебен случај*

*Забелешка за FD14: warehouseId се добива транзитивно од saleId (FD10) и од poId (FD11), но {warehouseId, productId} не е подмножество на примарниот клуч.

Идентификувани парцијални зависности што ја нарушуваат 2NF:

  1. FD5: productId → product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId
  2. FD10: saleId → sale_date_time, sale_total_amount, userId, customerId, warehouseId
  3. FD11: poId → po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId
  4. FD12: {saleId, productId} → saleitem_quantity, saleitem_unit_price_at_sale
  5. FD13: {poId, productId} → poitem_quantity, poitem_unit_cost

5. 2NF Декомпозиција

Чекор 5.1: Декомпозиција по FD5 (productId → ...)

Нарушува 2NF: productId е дел од примарниот клуч, а product_name, product_description, итн. зависат само од productId.

Декомпозиција:

R1(productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId)
   PK: productId

U1 = U - {product_name, product_description, product_sku, product_unit_price, product_reorder_level}

Проверка за lossless join:

  • R1 ∩ U1 = {productId, categoryId, supplierId}
  • productId → R1 (FD5)
  • Декомпозицијата е lossless ✓

Проверка за зачувување на FD: FD5 е зачувана во R1 ✓

Чекор 5.2: Декомпозиција по FD10 (saleId → ...)

Нарушува 2NF: saleId е дел од примарниот клуч на U1.

Декомпозиција:

R2(saleId, sale_date_time, sale_total_amount, userId, customerId, warehouseId)
   PK: saleId

U2 = U1 - {sale_date_time, sale_total_amount}

Проверка за lossless join:

  • R2 ∩ U2 = {saleId, userId, customerId, warehouseId}
  • saleId → R2 (FD10)
  • Декомпозицијата е lossless ✓

Чекор 5.3: Декомпозиција по FD11 (poId → ...)

Нарушува 2NF: poId е дел од примарниот клуч на U2.

Декомпозиција:

R3(poId, po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId)
   PK: poId

U3 = U2 - {po_order_date, po_expected_delivery_date, po_status}

Проверка за lossless join:

  • R3 ∩ U3 = {poId, supplierId, warehouseId}
  • poId → R3 (FD11)
  • Декомпозицијата е lossless ✓

Чекор 5.4: Декомпозиција по FD12 ({saleId, productId} → ...)

Нарушува 2NF: {saleId, productId} е подмножество на примарниот клуч.

Декомпозиција:

R4(saleId, productId, saleitem_quantity, saleitem_unit_price_at_sale)
   PK: {saleId, productId}

U4 = U3 - {saleitem_quantity, saleitem_unit_price_at_sale}

Проверка за lossless join:

  • R4 ∩ U4 = {saleId, productId}
  • {saleId, productId} → R4 (FD12)
  • Декомпозицијата е lossless ✓

Чекор 5.5: Декомпозиција по FD13 ({poId, productId} → ...)

Нарушува 2NF: {poId, productId} е подмножество на примарниот клуч.

Декомпозиција:

R5(poId, productId, poitem_quantity, poitem_unit_cost)
   PK: {poId, productId}

U5 = U4 - {poitem_quantity, poitem_unit_cost}

Проверка за lossless join:

  • R5 ∩ U5 = {poId, productId}
  • {poId, productId} → R5 (FD13)
  • Декомпозицијата е lossless ✓

Состојба после 2NF декомпозиција

R1(productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId)
   PK: productId

R2(saleId, sale_date_time, sale_total_amount, userId, customerId, warehouseId)
   PK: saleId

R3(poId, po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId)
   PK: poId

R4(saleId, productId, saleitem_quantity, saleitem_unit_price_at_sale)
   PK: {saleId, productId}

R5(poId, productId, poitem_quantity, poitem_unit_cost)
   PK: {poId, productId}

U5(saleId, poId, productId, userId, user_username, user_password, user_full_name, user_email, user_role, user_is_active,
   customerId, customer_name, customer_email, customer_phone, customer_address,
   categoryId, category_name, category_description,
   supplierId, supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address,
   warehouseId, warehouse_name, warehouse_location, warehouse_capacity,
   stock_quantity_on_hand, stock_last_updated)
   PK: {saleId, poId, productId}

6. 3NF Декомпозиција

Проверка за транзитивни зависности во секоја релација

R1(productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId)

Транзитивни зависности:

  • productId → categoryId → category_name, category_description?
    • category_name и category_description НЕ се во R1, па нема транзитивна зависност во оваа релација.
  • productId → supplierId → supplier_*?
    • supplier_* атрибутите НЕ се во R1.

Заклучок: R1 е во 3NF ✓

R2(saleId, sale_date_time, sale_total_amount, userId, customerId, warehouseId)

Транзитивни зависности:

  • saleId → userId → user_*?
    • user_* атрибутите НЕ се во R2.
  • saleId → customerId → customer_*?
    • customer_* атрибутите НЕ се во R2.
  • saleId → warehouseId → warehouse_*?
    • warehouse_* атрибутите НЕ се во R2.

Заклучок: R2 е во 3NF ✓

R3(poId, po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId)

Транзитивни зависности:

  • Слично како R2, supplier_* и warehouse_* не се во R3.

Заклучок: R3 е во 3NF ✓

R4(saleId, productId, saleitem_quantity, saleitem_unit_price_at_sale)

Транзитивни зависности:

  • Нема не-клучни атрибути кои одредуваат други не-клучни атрибути.

Заклучок: R4 е во 3NF ✓

R5(poId, productId, poitem_quantity, poitem_unit_cost)

Заклучок: R5 е во 3NF ✓

U5 - Проверка за транзитивни зависности

Примарен клуч на U5: {saleId, poId, productId}

Транзитивни зависности во U5:

  1. FD1 транзитивно: {saleId, poId, productId} → userId (преку R2/saleId) → user_username, user_password, user_full_name, user_email, user_role, user_is_active
    • userId не е клуч на U5, а user_* зависат од userId
    • НАРУШУВА 3NF
  1. FD4 транзитивно: {saleId, poId, productId} → customerId (преку R2/saleId) → customer_name, customer_email, customer_phone, customer_address
    • НАРУШУВА 3NF
  1. FD7 транзитивно: {saleId, poId, productId} → categoryId (преку R1/productId) → category_name, category_description
    • НАРУШУВА 3NF
  1. FD8 транзитивно: {saleId, poId, productId} → supplierId → supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address
    • НАРУШУВА 3NF
  1. FD9 транзитивно: {saleId, poId, productId} → warehouseId → warehouse_name, warehouse_location, warehouse_capacity
    • НАРУШУВА 3NF
  1. FD14: {warehouseId, productId} → stock_quantity_on_hand, stock_last_updated
    • warehouseId се добива транзитивно, а {warehouseId, productId} не е клуч на U5
    • НАРУШУВА 3NF

Чекор 6.1: Декомпозиција по FD1 (userId → user_*)

R6(userId, user_username, user_password, user_full_name, user_email, user_role, user_is_active)
   PK: userId

U6 = U5 - {user_username, user_password, user_full_name, user_email, user_role, user_is_active}

Проверка за lossless join:

  • R6 ∩ U6 = {userId}
  • userId → R6 (FD1)
  • Lossless ✓

Чекор 6.2: Декомпозиција по FD4 (customerId → customer_*)

R7(customerId, customer_name, customer_email, customer_phone, customer_address)
   PK: customerId

U7 = U6 - {customer_name, customer_email, customer_phone, customer_address}

Проверка за lossless join:

  • R7 ∩ U7 = {customerId}
  • customerId → R7 (FD4)
  • Lossless ✓

Чекор 6.3: Декомпозиција по FD7 (categoryId → category_*)

R8(categoryId, category_name, category_description)
   PK: categoryId

U8 = U7 - {category_name, category_description}

Проверка за lossless join:

  • R8 ∩ U8 = {categoryId}
  • categoryId → R8 (FD7)
  • Lossless ✓

Чекор 6.4: Декомпозиција по FD8 (supplierId → supplier_*)

R9(supplierId, supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address)
   PK: supplierId

U9 = U8 - {supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address}

Проверка за lossless join:

  • R9 ∩ U9 = {supplierId}
  • supplierId → R9 (FD8)
  • Lossless ✓

Чекор 6.5: Декомпозиција по FD9 (warehouseId → warehouse_*)

R10(warehouseId, warehouse_name, warehouse_location, warehouse_capacity)
   PK: warehouseId

U10 = U9 - {warehouse_name, warehouse_location, warehouse_capacity}

Проверка за lossless join:

  • R10 ∩ U10 = {warehouseId}
  • warehouseId → R10 (FD9)
  • Lossless ✓

Чекор 6.6: Декомпозиција по FD14 ({warehouseId, productId} → stock_*)

R11(warehouseId, productId, stock_quantity_on_hand, stock_last_updated)
   PK: {warehouseId, productId}

U11 = U10 - {stock_quantity_on_hand, stock_last_updated}

Проверка за lossless join:

  • R11 ∩ U11 = {warehouseId, productId}
  • {warehouseId, productId} → R11 (FD14)
  • Lossless ✓

Анализа на U11

U11(saleId, poId, productId, userId, customerId, categoryId, supplierId, warehouseId)
   PK: {saleId, poId, productId}

Атрибутите userId, customerId, warehouseId се веќе дел од R2 (Sale). Атрибутите categoryId, supplierId се веќе дел од R1 (Product).

U11 претставува врска меѓу продажби (saleId), нарачки (poId) и продукти (productId).

Прашање: Дали оваа релација има семантичка смисла?

Во реалноста:

  • Една продажба (saleId) е независна од една нарачка (poId)
  • Нивната врска е само преку productId и warehouseId

U11 може да се декомпонира понатаму, бидејќи атрибутите userId, customerId, warehouseId зависат само од saleId (FD10), а supplierId зависи само од poId или productId.

Но бидејќи овие атрибути се веќе издвоени во R2 и R1, U11 станува редундантна и може да се отстрани бидејќи информацијата е веќе зачувана во другите релации.

Состојба после 3NF декомпозиција

Релација Атрибути Примарен клуч
R1 (Product) productId, product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId productId
R2 (Sale) saleId, sale_date_time, sale_total_amount, userId, customerId, warehouseId saleId
R3 (PurchaseOrder) poId, po_order_date, po_expected_delivery_date, po_status, supplierId, warehouseId poId
R4 (SaleItem) saleId, productId, saleitem_quantity, saleitem_unit_price_at_sale {saleId, productId}
R5 (PurchaseOrderItem) poId, productId, poitem_quantity, poitem_unit_cost {poId, productId}
R6 (User) userId, user_username, user_password, user_full_name, user_email, user_role, user_is_active userId
R7 (Customer) customerId, customer_name, customer_email, customer_phone, customer_address customerId
R8 (Category) categoryId, category_name, category_description categoryId
R9 (Supplier) supplierId, supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address supplierId
R10 (Warehouse) warehouseId, warehouse_name, warehouse_location, warehouse_capacity warehouseId
R11 (WarehouseStock) warehouseId, productId, stock_quantity_on_hand, stock_last_updated {warehouseId, productId}

7. BCNF Декомпозиција

Проверка за BCNF

За секоја релација проверуваме: за секоја нетривијална FD X → Y, дали X е суперклуч?

R1 (Product)

FD Детерминант Суперклуч?
productId → сите productId ✓ ДА
product_sku → сите (FD6) product_sku ✓ ДА (кандидат клуч)

R1 е во BCNF

R2 (Sale)

FD Детерминант Суперклуч?
saleId → сите saleId ✓ ДА

R2 е во BCNF

R3 (PurchaseOrder)

FD Детерминант Суперклуч?
poId → сите poId ✓ ДА

R3 е во BCNF

R4 (SaleItem)

FD Детерминант Суперклуч?
{saleId, productId} → сите {saleId, productId} ✓ ДА

R4 е во BCNF

R5 (PurchaseOrderItem)

FD Детерминант Суперклуч?
{poId, productId} → сите {poId, productId} ✓ ДА

R5 е во BCNF

R6 (User)

FD Детерминант Суперклуч?
userId → сите userId ✓ ДА
user_username → сите (FD2) user_username ✓ ДА (кандидат клуч)
user_email → сите (FD3) user_email ✓ ДА (кандидат клуч)

R6 е во BCNF

R7 (Customer)

FD Детерминант Суперклуч?
customerId → сите customerId ✓ ДА

R7 е во BCNF

R8 (Category)

FD Детерминант Суперклуч?
categoryId → сите categoryId ✓ ДА

R8 е во BCNF

R9 (Supplier)

FD Детерминант Суперклуч?
supplierId → сите supplierId ✓ ДА

R9 е во BCNF

R10 (Warehouse)

FD Детерминант Суперклуч?
warehouseId → сите warehouseId ✓ ДА

R10 е во BCNF

R11 (WarehouseStock)

FD Детерминант Суперклуч?
{warehouseId, productId} → сите {warehouseId, productId} ✓ ДА

R11 е во BCNF

Заклучок: Сите релации се во BCNF.


8. Финален резултат и дискусија

8.1 Финални релации

User(userId, username, password, full_name, email, role, is_active)
  - Примарен клуч: userId
  - Кандидат клучеви: userId, username, email
  - Надворешни клучеви: -

Customer(customerId, name, email, phone, address)
  - Примарен клуч: customerId
  - Кандидат клучеви: customerId
  - Надворешни клучеви: -

Category(categoryId, name, description)
  - Примарен клуч: categoryId
  - Кандидат клучеви: categoryId
  - Надворешни клучеви: -

Supplier(supplierId, name, contact_person, phone, email, address)
  - Примарен клуч: supplierId
  - Кандидат клучеви: supplierId
  - Надворешни клучеви: -

Warehouse(warehouseId, name, location, capacity)
  - Примарен клуч: warehouseId
  - Кандидат клучеви: warehouseId
  - Надворешни клучеви: -

Product(productId, name, description, sku, unit_price, reorder_level, categoryId, supplierId)
  - Примарен клуч: productId
  - Кандидат клучеви: productId, sku
  - Надворешни клучеви: categoryId → Category, supplierId → Supplier

Sale(saleId, date_time, total_amount, userId, customerId, warehouseId)
  - Примарен клуч: saleId
  - Кандидат клучеви: saleId
  - Надворешни клучеви: userId → User, customerId → Customer, warehouseId → Warehouse

PurchaseOrder(poId, order_date, expected_delivery_date, status, supplierId, warehouseId)
  - Примарен клуч: poId
  - Кандидат клучеви: poId
  - Надворешни клучеви: supplierId → Supplier, warehouseId → Warehouse

SaleItem(saleId, productId, quantity, unit_price_at_sale)
  - Примарен клуч: {saleId, productId}
  - Кандидат клучеви: {saleId, productId}
  - Надворешни клучеви: saleId → Sale, productId → Product

PurchaseOrderItem(poId, productId, quantity, unit_cost)
  - Примарен клуч: {poId, productId}
  - Кандидат клучеви: {poId, productId}
  - Надворешни клучеви: poId → PurchaseOrder, productId → Product

WarehouseStock(warehouseId, productId, quantity_on_hand, last_updated)
  - Примарен клуч: {warehouseId, productId}
  - Кандидат клучеви: {warehouseId, productId}
  - Надворешни клучеви: warehouseId → Warehouse, productId → Product

8.2 Дискусија на разликите од моделот во Фаза P2

Преку процесот на нормализација, тргнувајќи од една универзална релација, дојдовме до истите 11 релации како во концептуалниот модел од Фаза P2. Ова покажува дека:

  1. Концептуалниот модел беше правилно дизајниран - ентитетите и нивните атрибути беа логички групирани.
  1. Процесот на нормализација го потврди дизајнот - секоја декомпозиција базирана на функционалните зависности резултираше со релација која одговара на ентитет од оригиналниот модел.
  1. Клучот на универзалната релација {saleId, poId, productId} беше идентификуван преку анализа на функционалните зависности и класификација лева/десна страна.
  1. Сите релации се во BCNF - нема функционална зависност каде детерминантот не е суперклуч.
  1. Декомпозицијата е lossless - оригиналната информација може да се реконструира.
  1. Сите функционални зависности се зачувани - секоја FD е зачувана во барем една од финалните релации.

8.3 Резиме на кандидат клучеви

Релација Примарен клуч Алтернативни кандидат клучеви
User userId username, email
Customer customerId -
Category categoryId -
Supplier supplierId -
Warehouse warehouseId -
Product productId sku
Sale saleId -
PurchaseOrder poId -
SaleItem {saleId, productId} -
PurchaseOrderItem {poId, productId} -
WarehouseStock {warehouseId, productId} -
Note: See TracWiki for help on using the wiki.