| Version 10 (modified by , 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}
Образложение:
- Сите три атрибути се сурогат клучеви кои не се менуваат со тек на време
- productId е понумерички и поефикасен за индексирање од product_sku (кој е VARCHAR)
- Сурогат клучевите обезбедуваат стабилност - ако се промени 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:
- FD5: productId → product_name, product_description, product_sku, product_unit_price, product_reorder_level, categoryId, supplierId
- 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
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:
- 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
- FD4 транзитивно: {saleId, poId, productId} → customerId (преку R2/saleId) → customer_name, customer_email, customer_phone, customer_address
- НАРУШУВА 3NF
- FD7 транзитивно: {saleId, poId, productId} → categoryId (преку R1/productId) → category_name, category_description
- НАРУШУВА 3NF
- FD8 транзитивно: {saleId, poId, productId} → supplierId → supplier_name, supplier_contact_person, supplier_phone, supplier_email, supplier_address
- НАРУШУВА 3NF
- FD9 транзитивно: {saleId, poId, productId} → warehouseId → warehouse_name, warehouse_location, warehouse_capacity
- НАРУШУВА 3NF
- 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. Ова покажува дека:
- Концептуалниот модел беше правилно дизајниран - ентитетите и нивните атрибути беа логички групирани.
- Процесот на нормализација го потврди дизајнот - секоја декомпозиција базирана на функционалните зависности резултираше со релација која одговара на ентитет од оригиналниот модел.
- Клучот на универзалната релација {saleId, poId, productId} беше идентификуван преку анализа на функционалните зависности и класификација лева/десна страна.
- Сите релации се во BCNF - нема функционална зависност каде детерминантот не е суперклуч.
- Декомпозицијата е lossless - оригиналната информација може да се реконструира.
- Сите функционални зависности се зачувани - секоја 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} | - |
