Normalizacja danych bez akademickiej teorii — praktyczny przykład w SQL Server

2026-09-15 · 2 min

Normalizacja często kojarzy się z teorią. W praktyce jej cel jest prosty:

Zapisać dane tak, aby nie powielać faktów i nie tworzyć sprzeczności.

Model początkowy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
CREATE TABLE dbo.OrderImport
(
    OrderNumber varchar(30) NOT NULL,
    OrderDate date NOT NULL,
    CustomerName nvarchar(200) NOT NULL,
    CustomerEmail nvarchar(320) NULL,
    ProductCode varchar(30) NOT NULL,
    ProductName nvarchar(200) NOT NULL,
    UnitPrice decimal(18,2) NOT NULL,
    Quantity int NOT NULL
);

Problem pojawia się, gdy klient składa wiele zamówień lub jedno zamówienie ma wiele pozycji.

Jakie problemy powstają?

Anomalia aktualizacji

Zmiana e-maila klienta wymaga poprawienia wielu wierszy.

Anomalia dodawania

Nie można dodać produktu, dopóki nie pojawi się w zamówieniu.

Anomalia usuwania

Usunięcie ostatniego zamówienia może usunąć jedyną informację o kliencie.

Oddziel klienta

1
2
3
4
5
6
7
CREATE TABLE dbo.Customer
(
    CustomerId int IDENTITY(1,1) NOT NULL,
    CustomerName nvarchar(200) NOT NULL,
    Email nvarchar(320) NULL,
    CONSTRAINT PK_Customer PRIMARY KEY CLUSTERED (CustomerId)
);

Oddziel produkt

1
2
3
4
5
6
7
8
9
CREATE TABLE dbo.Product
(
    ProductId int IDENTITY(1,1) NOT NULL,
    ProductCode varchar(30) NOT NULL,
    ProductName nvarchar(200) NOT NULL,
    CurrentUnitPrice decimal(18,2) NOT NULL,
    CONSTRAINT PK_Product PRIMARY KEY CLUSTERED (ProductId),
    CONSTRAINT UQ_Product_ProductCode UNIQUE (ProductCode)
);

Nagłówek zamówienia

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
CREATE TABLE dbo.SalesOrder
(
    SalesOrderId bigint IDENTITY(1,1) NOT NULL,
    OrderNumber varchar(30) NOT NULL,
    OrderDate date NOT NULL,
    CustomerId int NOT NULL,
    CONSTRAINT PK_SalesOrder PRIMARY KEY CLUSTERED (SalesOrderId),
    CONSTRAINT UQ_SalesOrder_OrderNumber UNIQUE (OrderNumber),
    CONSTRAINT FK_SalesOrder_Customer
        FOREIGN KEY (CustomerId)
        REFERENCES dbo.Customer(CustomerId)
);

Pozycje zamówienia

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
CREATE TABLE dbo.SalesOrderLine
(
    SalesOrderLineId bigint IDENTITY(1,1) NOT NULL,
    SalesOrderId bigint NOT NULL,
    ProductId int NOT NULL,
    Quantity int NOT NULL,
    UnitPrice decimal(18,2) NOT NULL,
    CONSTRAINT PK_SalesOrderLine
        PRIMARY KEY CLUSTERED (SalesOrderLineId),
    CONSTRAINT FK_SalesOrderLine_SalesOrder
        FOREIGN KEY (SalesOrderId)
        REFERENCES dbo.SalesOrder(SalesOrderId),
    CONSTRAINT FK_SalesOrderLine_Product
        FOREIGN KEY (ProductId)
        REFERENCES dbo.Product(ProductId),
    CONSTRAINT CK_SalesOrderLine_Quantity CHECK (Quantity > 0)
);

Co zyskaliśmy?

Każdy fakt ma jedno miejsce:

  • klient w Customer,
  • produkt w Product,
  • zamówienie w SalesOrder,
  • pozycja w SalesOrderLine.

Podsumowanie

Normalizacja nie jest akademickim rytuałem. Eliminuje powtórzenia i niespójności.

Spokojny projektant zaczyna od pytania:

Gdzie znajduje się jedyne wiarygodne miejsce zapisu danego faktu?


Tagi: SQLServer , DataModeling , Normalization , DatabaseDesign , DBA

Marcin Pytlik
LinkedIn · GitHub

Marcin Pytlik

LinkedIn · GitHub