Narzędzia
Portfolio Roadmapa Słownik Blog Portal dla BA
← Wszystkie artykuły
SQL i bazy danych 2026-06-01

ERD i modelowanie danych - poradnik dla analityka

13 min czytania

Encje, atrybuty, relacje, normalizacja - wszystko co analityk biznesowy powinien wiedzieć o diagramach ERD. Z ćwiczeniem praktycznym.

ERD modelowanie danych Crow's Foot normalizacja SQL

Analityk dostarczył idealną specyfikację: 60 stron user stories, kryteria akceptacji, mockupy. Zespół zaczął kodować i po dwóch tygodniach utknął na pozornie banalnym pytaniu: „Czy jedno zamówienie może mieć wiele adresów dostawy? A jeden klient - wiele zamówień opłaconych jedną fakturą?". W specyfikacji tego nie było. Nikt nie pomyślał o danych - tylko o ekranach. Zespół musiał trzy razy przerabiać schemat bazy, bo struktura danych była przemyślana po fakcie, a nie zaprojektowana z góry.

Diagram związków encji (ERD) to narzędzie, które temu zapobiega. Jeden dobry diagram na jednej stronie odpowiada na pytania o relacje, których setki stron tekstu nie dotykają. W tym artykule nauczę Cię czytać i tworzyć ERD w notacji Crow's Foot, rozumieć normalizację (1NF-3NF na konkretnych przykładach) i zaprojektować model danych dla sklepu e-commerce krok po kroku. To umiejętność, która zamienia analityka „od ekranów" w analityka, który rozumie, jak działa system pod spodem.

Czym jest ERD i dlaczego analityk musi go znać

ERD (Entity-Relationship Diagram) to graficzna reprezentacja danych w systemie. Pokazuje trzy rzeczy: encje (rzeczy, o których przechowujemy informacje - Klient, Zamówienie, Produkt), atrybuty (cechy encji - imię klienta, cena produktu) oraz związki (jak encje się ze sobą łączą - Klient składa Zamówienia).

„Ale ja nie jestem projektantem baz danych" - słyszę to często. I to prawda, że finalny schemat fizyczny rysuje architekt lub deweloper. Ale analityk biznesowy musi rozumieć model danych, bo to on tłumaczy świat biznesu na strukturę, którą system będzie przechowywać. Bez modelu danych pełno jest dwuznaczności: czy „klient" i „kontakt" to to samo? Czy produkt może istnieć bez kategorii? ERD zmusza do odpowiedzi na te pytania przed kodowaniem.

Trzy poziomy modelu danych

  • Konceptualny - encje i związki, bez szczegółów technicznych. Język biznesu. „Klient składa zamówienia, zamówienie zawiera produkty." To poziom, na którym najczęściej pracuje analityk.
  • Logiczny - dodajemy atrybuty, klucze, typy związków, normalizujemy. Wciąż niezależny od konkretnej bazy danych.
  • Fizyczny - konkretne typy danych, indeksy, nazwy tabel w PostgreSQL/MySQL/Oracle. Domena architekta i dewelopera.

Jako analityk celujesz głównie w poziom konceptualny i logiczny. To wystarczy, by precyzyjnie zakomunikować zespołowi, jak ma wyglądać struktura informacji.

Notacja Crow's Foot - czytanie „kurzej stopki"

Crow's Foot (notacja „kurzej stopki") to najpopularniejszy sposób oznaczania kardynalności związków na ERD. Nazwa bierze się od symbolu przypominającego ptasią stopę - trzech rozchodzących się linii oznaczających „wiele". Zaletą tej notacji jest to, że na jednym końcu linii czytasz od razu dwie informacje: maksimum (jeden czy wiele) i minimum (zero czy co najmniej jeden - czyli opcjonalność).

Symbole na końcach linii

SymbolZnaczenieCzyta się
│ (kreska)Dokładnie jeden (one, mandatory)„jeden i tylko jeden"
○│ (kółko + kreska)Zero lub jeden (optional one)„zero albo jeden"
< (kurza stopka)Jeden lub wiele (many, mandatory)„jeden albo wiele"
○< (kółko + stopka)Zero lub wiele (optional many)„zero, jeden albo wiele"

Symbol bliższy encji oznacza maksimum (czy stopka = wiele, czy kreska = jeden), a symbol dalszy od encji oznacza minimum (czy kółko = opcjonalne/zero, czy kreska = obowiązkowe/co najmniej jeden). To najważniejsze i często mylone - czytasz parę symboli, nie pojedynczy.

Trzy typy kardynalności

  • Jeden-do-jednego (1:1) - np. Pracownik ma jedną Kartę dostępu, Karta należy do jednego Pracownika. Rzadkie; często sygnał, że dane można scalić w jedną tabelę.
  • Jeden-do-wielu (1:N) - najczęstszy. Klient składa wiele Zamówień, ale każde Zamówienie należy do jednego Klienta. Realizowane przez klucz obcy po stronie „wiele".
  • Wiele-do-wielu (M:N) - np. Zamówienie zawiera wiele Produktów, a Produkt występuje w wielu Zamówieniach. W bazie relacyjnej M:N zawsze rozbija się na tabelę pośredniczącą (junction/associative table) - o tym za chwilę.

Jak czytać przykładowy związek

KLIENT ──│────────<○ ZAMÓWIENIE

Czytamy z dwóch stron:
• Jeden KLIENT może mieć zero lub wiele ZAMÓWIEŃ (kółko + stopka po stronie zamówienia).
• Jedno ZAMÓWIENIE należy do dokładnie jednego KLIENTA (kreska + kreska po stronie klienta).

To jedno zdanie z diagramu zastępuje akapit tekstu i nie pozostawia miejsca na interpretację. Właśnie dlatego ERD jest tak potężny w komunikacji.

Jak znaleźć encje i atrybuty w wymaganiach

Najtrudniejsza część modelowania to nie rysowanie, tylko decyzja, co w ogóle modelować. Istnieje prosta heurystyka, która pomaga zacząć: czytaj wymagania i podkreślaj rzeczowniki. Większość encji to rzeczowniki (klient, zamówienie, faktura, lekarz), a atrybuty to rzeczowniki opisujące cechy (imię, cena, data). Czasowniki zwykle wskazują na związki („klient składa zamówienie", „lekarz prowadzi wizytę").

To dopiero punkt startu - potem zadajesz pytania weryfikujące:

  • Czy o tej rzeczy trzymamy więcej niż jedną informację? Jeśli tak, to prawdopodobnie encja, nie atrybut. „Adres" z polami ulica, miasto, kod może być encją, jeśli klient ma ich wiele.
  • Ile ich może istnieć w relacji? To pytanie wyznacza kardynalność. „Czy pacjent może mieć wielu lekarzy prowadzących?" - odpowiedź decyduje o 1:N vs M:N.
  • Czy ta rzecz ma własny cykl życia? Jeśli coś powstaje, zmienia stan i znika niezależnie od innych encji (jak zamówienie), to mocny kandydat na osobną encję.

Encje słabe i silne

Encja silna istnieje samodzielnie (Klient, Produkt). Encja słaba nie ma sensu bez encji nadrzędnej - jej istnienie zależy od innej. Klasyczny przykład: Pozycja_zamówienia nie istnieje bez Zamówienia. Pozycja jest encją słabą, identyfikowaną częściowo przez klucz zamówienia. Rozpoznawanie encji słabych pomaga modelować zależności egzystencjalne (gdy usuwasz zamówienie, jego pozycje też powinny zniknąć - to kaskadowe usuwanie).

Normalizacja - porządkowanie danych

Normalizacja to proces organizowania danych tak, by wyeliminować redundancję i anomalie (problemy przy wstawianiu, aktualizacji i usuwaniu). Brzmi akademicko, ale chodzi o coś bardzo praktycznego: żeby ta sama informacja nie była przechowywana w wielu miejscach, bo wtedy łatwo o sprzeczności.

Problem: tabela nieznormalizowana

Wyobraź sobie jedną tabelę „Zamówienia" trzymającą wszystko:

Zamowienie_ID | Klient        | Email_klienta    | Produkty                          | Adres_klienta
1001          | Anna Nowak    | [email protected]     | Laptop; Mysz; Torba               | ul. Polna 5, Kraków
1002          | Anna Nowak    | [email protected]     | Klawiatura                        | ul. Polna 5, Kraków

Co tu jest nie tak? Po pierwsze, kolumna „Produkty" trzyma kilka wartości w jednej komórce (nie da się sensownie zapytać „ile sprzedano myszek?"). Po drugie, dane Anny powtarzają się w każdym wierszu - gdy zmieni e-mail, trzeba poprawić wiele miejsc (anomalia aktualizacji). Normalizacja to naprawia.

Pierwsza postać normalna (1NF)

Zasada: każda komórka zawiera jedną, atomową wartość, brak grup powtarzających się. Rozbijamy kolumnę „Produkty" - każda pozycja zamówienia to osobny wiersz:

Pozycja_ID | Zamowienie_ID | Produkt     | Klient     | Email_klienta
1          | 1001          | Laptop      | Anna Nowak | [email protected]
2          | 1001          | Mysz        | Anna Nowak | [email protected]
3          | 1001          | Torba       | Anna Nowak | [email protected]
4          | 1002          | Klawiatura  | Anna Nowak | [email protected]

Druga postać normalna (2NF)

Warunek: tabela jest w 1NF i każdy atrybut niekluczowy zależy od całego klucza głównego, a nie od jego części (dotyczy kluczy złożonych). W naszej tabeli pozycji klucz to (Zamowienie_ID + Produkt). Dane klienta zależą tylko od Zamowienie_ID, nie od Produktu - to częściowa zależność. Wydzielamy je do osobnej tabeli:

-- Tabela ZAMÓWIENIA
Zamowienie_ID | Klient     | Email_klienta
1001          | Anna Nowak | [email protected]
1002          | Anna Nowak | [email protected]

-- Tabela POZYCJE_ZAMÓWIENIA
Pozycja_ID | Zamowienie_ID | Produkt
1          | 1001          | Laptop
2          | 1001          | Mysz

Trzecia postać normalna (3NF)

Warunek: tabela jest w 2NF i nie ma zależności przechodnich - atrybut niekluczowy nie może zależeć od innego atrybutu niekluczowego. W tabeli Zamówienia „Email_klienta" zależy od „Klient", a nie wprost od „Zamowienie_ID". To zależność przechodnia. Wydzielamy klienta do własnej encji:

-- Tabela KLIENCI
Klient_ID | Imie_nazwisko | Email
1         | Anna Nowak    | [email protected]

-- Tabela ZAMÓWIENIA (z kluczem obcym do klienta)
Zamowienie_ID | Klient_ID
1001          | 1
1002          | 1

Teraz e-mail Anny jest w jednym miejscu. Zmiana = jedna aktualizacja, zero ryzyka sprzeczności. To jest cała idea 3NF: każdy fakt przechowywany dokładnie raz.

Praktyczna mnemotechnika 3NF, którą podaję na szkoleniach: każdy atrybut niekluczowy musi zależeć „od klucza, całego klucza i tylko od klucza" (the key, the whole key, and nothing but the key). 1NF = atomowe wartości, 2NF = cały klucz, 3NF = tylko klucz.

Kiedy świadomie denormalizować

Normalizacja to ideał, ale nie dogmat. Czasem dla wydajności (mniej JOIN-ów przy ogromnym ruchu) celowo dopuszcza się redundancję - to denormalizacja. Klasyczny przykład: zapisanie ceny produktu wprost w pozycji zamówienia. Wydaje się to redundantne, ale jest poprawne: cena w zamówieniu musi pozostać historyczną ceną z momentu zakupu, nawet gdy cennik produktu się zmieni. To nie błąd normalizacji - to świadoma decyzja biznesowa.

Mini-przykład end-to-end: ERD dla e-commerce (MediFlow Shop)

Zaprojektujmy model danych dla prostego sklepu e-commerce - załóżmy, że MediFlow uruchamia sklep ze sprzętem medycznym i suplementami. Przejdziemy od encji do gotowego ERD z rozbiciem relacji M:N.

Krok 1: Identyfikacja encji

Z rozmów z biznesem wyłaniają się rzeczowniki, o których trzymamy dane: Klient, Zamówienie, Produkt, Kategoria, Pozycja_zamówienia, Płatność.

Krok 2: Atrybuty i klucze

  • KLIENT: klient_id (PK), imie_nazwisko, email, telefon
  • ZAMÓWIENIE: zamowienie_id (PK), klient_id (FK), data, status
  • PRODUKT: produkt_id (PK), nazwa, cena, stan_magazynowy, kategoria_id (FK)
  • KATEGORIA: kategoria_id (PK), nazwa
  • POZYCJA_ZAMÓWIENIA: pozycja_id (PK), zamowienie_id (FK), produkt_id (FK), ilosc, cena_w_momencie_zakupu
  • PŁATNOŚĆ: platnosc_id (PK), zamowienie_id (FK), kwota, metoda, status

Krok 3: Związki i kardynalność

  • KLIENT 1:N ZAMÓWIENIE - jeden klient ma wiele zamówień; każde zamówienie należy do jednego klienta.
  • KATEGORIA 1:N PRODUKT - jedna kategoria grupuje wiele produktów; produkt należy do jednej kategorii.
  • ZAMÓWIENIE 1:1 PŁATNOŚĆ - przyjmijmy jedną płatność na zamówienie (można rozszerzyć na 1:N).
  • ZAMÓWIENIE M:N PRODUKT - to klucz całego modelu: zamówienie zawiera wiele produktów, produkt jest w wielu zamówieniach.

Krok 4: Rozbicie M:N na tabelę pośredniczącą

Baza relacyjna nie umie wprost przechować relacji wiele-do-wielu. Rozbijamy ją na dwie relacje 1:N przez encję pośredniczącą - i tą encją jest właśnie POZYCJA_ZAMÓWIENIA:

ZAMÓWIENIE  ──│────<  POZYCJA_ZAMÓWIENIA  >────│──  PRODUKT

• Jedno ZAMÓWIENIE ma wiele POZYCJI (1:N)
• Jeden PRODUKT występuje w wielu POZYCJACH (1:N)
• POZYCJA łączy dokładnie jedno zamówienie z jednym produktem

Co ważne, tabela pośrednicząca nie jest tylko „klejem" - przechowuje dane o samej relacji: ilość zamówionych sztuk i cenę w momencie zakupu. Bez niej nie da się zapisać, że klient kupił 3 sztuki produktu za cenę z dnia zakupu. To częsty „aha-moment" u osób uczących się modelowania.

Krok 5: Gotowy schemat (uproszczony SQL)

CREATE TABLE klienci (
    klient_id      SERIAL PRIMARY KEY,
    imie_nazwisko  VARCHAR(120) NOT NULL,
    email          VARCHAR(160) UNIQUE NOT NULL
);

CREATE TABLE kategorie (
    kategoria_id   SERIAL PRIMARY KEY,
    nazwa          VARCHAR(80) NOT NULL
);

CREATE TABLE produkty (
    produkt_id     SERIAL PRIMARY KEY,
    nazwa          VARCHAR(160) NOT NULL,
    cena           NUMERIC(10,2) NOT NULL,
    stan_magazynowy INTEGER NOT NULL DEFAULT 0,
    kategoria_id   INTEGER REFERENCES kategorie(kategoria_id)
);

CREATE TABLE zamowienia (
    zamowienie_id  SERIAL PRIMARY KEY,
    klient_id      INTEGER NOT NULL REFERENCES klienci(klient_id),
    data           TIMESTAMP NOT NULL DEFAULT NOW(),
    status         VARCHAR(30) NOT NULL DEFAULT 'nowe'
);

CREATE TABLE pozycje_zamowienia (
    pozycja_id     SERIAL PRIMARY KEY,
    zamowienie_id  INTEGER NOT NULL REFERENCES zamowienia(zamowienie_id),
    produkt_id     INTEGER NOT NULL REFERENCES produkty(produkt_id),
    ilosc          INTEGER NOT NULL CHECK (ilosc > 0),
    cena_w_zakupie NUMERIC(10,2) NOT NULL
);

Ten schemat jest w 3NF, obsługuje relację M:N przez tabelę pozycji i poprawnie zachowuje historyczną cenę zakupu. Od konceptu na tablicy do gotowej struktury - to jest droga, którą analityk powinien umieć przejść.

Związki specjalne, które warto znać

Poza prostymi 1:N i M:N w realnych modelach pojawiają się konstrukcje, które potrafią zaskoczyć początkujących. Warto je rozpoznawać.

Związek rekurencyjny (samozłączenie)

Czasem encja łączy się sama ze sobą. Klasyczny przykład: Pracownik ma przełożonego, który też jest Pracownikiem. Modelujesz to kluczem obcym wskazującym na tę samą tabelę (przelozony_id REFERENCES pracownicy(pracownik_id)). Podobnie kategorie produktów z podkategoriami albo komentarze z odpowiedziami. To potężny wzorzec do hierarchii i struktur drzewiastych.

Supertyp i podtyp (dziedziczenie)

Gdy kilka encji dzieli wspólne atrybuty, ale ma też własne, modelujesz to jako supertyp z podtypami. Przykład: Użytkownik (supertyp: id, email, hasło) z podtypami Pacjent (PESEL, historia chorób) i Lekarz (numer PWZ, specjalizacja). Wspólne dane trzymasz raz, specyficzne - w tabelach podtypów. To odpowiednik dziedziczenia z programowania obiektowego przeniesiony do modelu danych.

Atrybut wielowartościowy

Gdy atrybut może mieć wiele wartości (klient ma kilka numerów telefonu), nie da się go trzymać w jednej kolumnie bez łamania 1NF. Rozwiązanie: wydzielasz osobną encję (Telefony) w relacji 1:N z klientem. To samo dotyczy tagów, ról, adresów - gdy „ile ich może być?" daje odpowiedź „wiele", rodzi się nowa encja.

Crow's Foot a inne notacje

Crow's Foot jest dziś dominujący, ale spotkasz też inne zapisy - warto je rozpoznawać, by nie zgubić się przy cudzym diagramie.

NotacjaJak oznacza kardynalnośćGdzie spotkasz
Crow's FootSymbole graficzne (stopka, kreska, kółko)Najpopularniejsza, narzędzia typu Lucidchart, dbdiagram, draw.io
ChenRomby związków, liczby 1/N przy liniachAkademicka, klasyczne podręczniki
UML (diagram klas)Krotności typu 1, 0..1, 1..*, *Projekty zorientowane obiektowo, integracja z modelem klas

Moja rekomendacja dla analityka: ucz się Crow's Foot jako podstawy (najczęściej go zobaczysz i najłatwiej go czytać nietechnicznym interesariuszom), ale rozumiej krotności UML, bo w projektach obiektowych diagram klas często pełni rolę modelu danych. Notacja Chena jest dziś rzadka poza salą wykładową.

Najczęstsze błędy w modelowaniu danych

1. Nierozbita relacja M:N

Najczęstszy błąd początkujących: próba połączenia dwóch encji relacją wiele-do-wielu bez tabeli pośredniczącej. W bazie relacyjnej to niewykonalne. Każde M:N zawsze wymaga encji łączącej.

2. Wiele wartości w jednej komórce

Kolumna „produkty" z wartością „Laptop; Mysz; Torba" łamie 1NF i czyni dane bezużytecznymi do zapytań. Jedna komórka = jedna wartość atomowa.

3. Brak kluczy głównych

Encja bez unikalnego identyfikatora (PK) to encja, której wierszy nie da się jednoznacznie wskazać. Każda tabela potrzebuje klucza głównego.

4. Mylenie atrybutu z encją

Czy „adres" to atrybut klienta, czy osobna encja? Zależy od kontekstu: jeśli klient ma wiele adresów (dostawy, faktury), adres staje się osobną encją w relacji 1:N. Modelowanie to ciągłe zadawanie pytania „ile ich może być?".

5. Przesadna normalizacja

Rozbijanie wszystkiego do absurdu (np. osobna tabela na kody pocztowe „dla czystości") generuje dziesiątki JOIN-ów i komplikuje system bez realnej korzyści. Normalizuj do 3NF, denormalizuj świadomie tam, gdzie ma to sens biznesowy lub wydajnościowy.

6. Ignorowanie cen historycznych

Pobieranie ceny produktu z tabeli produktów w momencie wyświetlania starego zamówienia daje błędne kwoty po zmianie cennika. Cenę zakupu trzeba „zamrozić" w pozycji zamówienia.

FAQ - ERD i modelowanie danych

Czy analityk biznesowy musi umieć projektować bazy danych?

Nie musi rysować fizycznego schematu z indeksami i typami - to robi architekt lub deweloper. Ale musi umieć tworzyć i czytać model konceptualny/logiczny (encje, atrybuty, związki, kardynalność), bo to on przekłada wymagania biznesowe na strukturę danych i wychwytuje dwuznaczności, zanim trafią do kodu.

Jak czytać symbole notacji Crow's Foot?

Na każdym końcu linii są dwa symbole. Bliższy encji oznacza maksimum (kreska = jeden, kurza stopka = wiele), dalszy oznacza minimum (kółko = zero/opcjonalne, kreska = co najmniej jeden/obowiązkowe). Czytasz związek z obu stron, np. „jeden klient ma zero lub wiele zamówień, a zamówienie należy do dokładnie jednego klienta".

Do której postaci normalnej normalizować?

W większości projektów biznesowych celem jest trzecia postać normalna (3NF) - eliminuje redundancję i typowe anomalie, pozostając praktyczna. Wyższe postacie (BCNF, 4NF) bywają potrzebne w szczególnych przypadkach. Denormalizacja jest dopuszczalna świadomie, dla wydajności lub zachowania danych historycznych.

Czym różni się klucz główny od klucza obcego?

Klucz główny (PK) jednoznacznie identyfikuje wiersz w swojej tabeli - jest unikalny i niepusty. Klucz obcy (FK) to kolumna wskazująca na klucz główny innej tabeli - to mechanizm, który realizuje związki między encjami (np. klient_id w tabeli zamówień wskazuje, do którego klienta należy zamówienie).

Jak zamodelować relację wiele-do-wielu?

Rozbijając ją na dwie relacje jeden-do-wielu za pomocą tabeli pośredniczącej (junction table). Np. relację Zamówienie-Produkt realizuje tabela Pozycje_zamówienia, która łączy konkretne zamówienie z konkretnym produktem i dodatkowo przechowuje atrybuty relacji, takie jak ilość i cena zakupu.

Podsumowanie

ERD to most między światem biznesu a strukturą systemu. Notacja Crow's Foot pozwala precyzyjnie zakomunikować kardynalność związków, normalizacja (1NF-3NF) chroni przed redundancją i anomaliami, a umiejętność rozbicia relacji M:N na tabelę pośredniczącą to różnica między modelem, który działa, a takim, który trzeba przepisywać. Analityk, który myśli o danych, a nie tylko o ekranach, oszczędza zespołowi tygodnie przeróbek.

Modelowanie danych idzie w parze z umiejętnością ich odpytywania. Po zaprojektowaniu schematu przećwicz zapytania w naszym poradniku SQL dla analityka biznesowego i odwiedź interaktywny sandbox SQL na platformie. Przyda się też wiedza o diagramach UML w praktyce oraz o diagramach przepływu danych (DFD). Definicje pojęć znajdziesz w słowniku analityka.

Czytaj też

Newsletter Analify

Nowe artykuły, porady i materiały dla analityków - prosto na email.

Dołącz do społeczności analityków biznesowych

Rozwijaj kompetencje, ucz się od praktyków i buduj karierę w analizie biznesowej.

Dołącz do Analify
SK

Sebastian Koczyk

Analityk biznesowy, twórca Analify.pl

Dołącz do społeczności analityków biznesowych - szkolenia wideo, prelekcje na żywo i wsparcie ekspertów

Sprawdź Analify