Projekt logiczny
1. Projektowanie tabel w oparciu o diagram ERD
Skrypt SQL tworzący baze do projektu:
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
CREATE SEQUENCE tab_typy_statusu_id_statusu_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_typy_statusu (
id_statusu integer NOT NULL DEFAULT
nextval('tab_typy_statusu_id_statusu_seq') PRIMARY KEY,
opis character varying(50) NOT NULL
);
CREATE SEQUENCE tab_pracownicy_id_pracownika_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_pracownicy (
id_pracownika integer NOT NULL DEFAULT
nextval('tab_pracownicy_id_pracownika_seq') PRIMARY KEY,
imie character varying(25) NOT NULL,
nazwisko character varying(50) NOT NULL,
login character varying(25),
password character varying(32),
telefon integer NOT NULL CHECK (((telefon)::text ~* '[0-9]{9,}'::text)),
email character varying(255) CHECK (((email) ~*
'[a-zA-Z]{1}[a-zA-Z0-9.]{0,}@[a-z0-9A-Z]{1,}(.[a-z0-9A-Z]{1,}){1,}$')),
status integer NOT NULL REFERENCES tab_typy_statusu(id_statusu) ON UPDATE RESTRICT
);
CREATE SEQUENCE tab_produkty_id_produktu_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_produkty (
id_produktu integer NOT NULL DEFAULT
nextval('tab_produkty_id_produktu_seq') PRIMARY KEY,
nazwa character varying(150) NOT NULL,
cena_netto double precision NOT NULL,
stawka_podatkowa smallint
);
CREATE SEQUENCE tab_kategoria_id_kategorii_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_kategoria (
id_kategorii integer NOT NULL DEFAULT
nextval('tab_kategoria_id_kategorii_seq') PRIMARY KEY,
nazwa character varying(200) NOT NULL,
opis character varying(600)
);
CREATE TABLE tab_kategoria_produktu_pomocnicza (
id_kategorii integer NOT NULL REFERENCES tab_kategoria(id_kategorii)
ON UPDATE RESTRICT,
id_produktu integer NOT NULL REFERENCES tab_produkty(id_produktu)
ON UPDATE RESTRICT
);
CREATE SEQUENCE tab_kontrahenci_id_kontrahenta_seq
INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_kontrahenci (
id_kontrahenta integer NOT NULL DEFAULT
nextval('tab_kontrahenci_id_kontrahenta_seq') PRIMARY KEY,
nazwa character varying(100) NOT NULL,
nip character varying(10) NOT NULL CHECK (((nip) ~* '[0-9]{10}')),
miasto character varying(40) NOT NULL,
ulica character varying(40) NOT NULL,
nr_domu character varying(10) NOT NULL,
kod_pocztowy character varying(5) NOT NULL CHECK
(((kod_pocztowy) ~* '[0-9]{5}'))
);
CREATE TABLE tab_email_kontrahenta (
id_kontrahenta integer NOT NULL REFERENCES tab_kontrahenci(id_kontrahenta)
ON UPDATE RESTRICT,
email character varying(255) NOT NULL CHECK (((email) ~*
'[a-zA-Z]{1}[a-zA-Z0-9.]{0,}@[a-z0-9A-Z]{1,}(.[a-z0-9A-Z]{1,}){1,}$')),
opis character varying(150)
);
CREATE SEQUENCE tab_magazyn_id_magazynowy_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_magazyn (
id_magazynowy integer NOT NULL DEFAULT
nextval('tab_magazyn_id_magazynowy_seq') PRIMARY KEY,
id_produktu integer NOT NULL REFERENCES tab_produkty(id_produktu)
ON UPDATE RESTRICT,
ilosc integer NOT NULL
);
CREATE TABLE tab_opis (
id_produktu integer NOT NULL PRIMARY KEY REFERENCES tab_produkty(id_produktu)
ON UPDATE RESTRICT,
opis character varying(600)
);
CREATE TABLE tab_polozenia (
id_magazynowy integer NOT NULL PRIMARY KEY REFERENCES tab_magazyn(id_magazynowy)
ON UPDATE RESTRICT,
polozenie character varying(150) NOT NULL
);
CREATE SEQUENCE tab_przedstawiciele_kontrahenta_id_przedstawiciela_seq
INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_przedstawiciele_kontrahenta (
id_przedstawiciela integer NOT NULL PRIMARY KEY DEFAULT
nextval('tab_przedstawiciele_kontrahenta_id_przedstawiciela_seq'),
id_kontrahenta integer NOT NULL REFERENCES tab_kontrahenci(id_kontrahenta)
ON DELETE RESTRICT,
imie character varying(25) NOT NULL,
nazwisko character varying(50) NOT NULL,
telefon integer NOT NULL CHECK
(((telefon)::text ~* '[0-9]{9,}'::text)),
email character varying(255) CHECK (((email) ~*
'[a-zA-Z]{1}[a-zA-Z0-9.]{0,}@[a-z0-9A-Z]{1,}(.[a-z0-9A-Z]{1,}){1,}$')),
opis character varying(600)
);
CREATE TABLE tab_zamowienie (
id_zamowienia integer NOT NULL PRIMARY KEY,
id_kontrahenta integer NOT NULL REFERENCES tab_kontrahenci(id_kontrahenta)
ON UPDATE RESTRICT,
data_zamowienia timestamp without time zone NOT NULL,
data_realizacji timestamp without time zone NOT NULL,
id_pracownika integer NOT NULL REFERENCES tab_pracownicy(id_pracownika)
ON UPDATE RESTRICT,
id_przedstawiciela integer NOT NULL REFERENCES
tab_przedstawiciele_kontrahenta(id_przedstawiciela) ON UPDATE RESTRICT
);
CREATE SEQUENCE tab_spis_zamowien_id_szczegolowego_zamowienia_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_spis_zamowien (
id_szczegolowego_zamowienia integer NOT NULL PRIMARY KEY DEFAULT
nextval('tab_spis_zamowien_id_szczegolowego_zamowienia_seq'),
id_zamowienia integer NOT NULL REFERENCES tab_zamowienie(id_zamowienia)
ON UPDATE RESTRICT,
id_produktu integer NOT NULL REFERENCES tab_produkty(id_produktu)
ON UPDATE RESTRICT,
ilosc integer NOT NULL
);
CREATE SEQUENCE tab_typy_rabatu_id_rabatu_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_typy_rabatu (
id_rabatu integer NOT NULL
DEFAULT nextval('tab_typy_rabatu_id_rabatu_seq') PRIMARY KEY,
opis character varying(50) NOT NULL
);
CREATE TABLE tab_rabat (
id_szczegolowego_zamowienia integer NOT NULL PRIMARY KEY REFERENCES
tab_spis_zamowien(id_szczegolowego_zamowienia) ON UPDATE RESTRICT,
wartosc_upustu integer NOT NULL,
typ integer NOT NULL REFERENCES tab_typy_rabatu(id_rabatu) ON UPDATE RESTRICT
);
CREATE TABLE tab_produkcja (
id_szczegolowego_zamowienia integer NOT NULL PRIMARY KEY
REFERENCES tab_spis_zamowien(id_szczegolowego_zamowienia)
ON UPDATE RESTRICT,
status character varying(30) NOT NULL
);
CREATE TABLE tab_magazyn_rezerwacje (
id_magazynowy integer NOT NULL REFERENCES tab_magazyn(id_magazynowy)
ON UPDATE RESTRICT,
id_szczegolowego_zamowienia integer NOT NULL
REFERENCES tab_spis_zamowien(id_szczegolowego_zamowienia) ON UPDATE RESTRICT
);
CREATE TABLE tab_telefon_kontrahenta (
id_kontrahenta integer NOT NULL REFERENCES tab_kontrahenci(id_kontrahenta)
ON UPDATE RESTRICT,
telefon integer NOT NULL CHECK (((telefon)::text ~* '[0-9]{9,}'::text)),
opis character varying(150),
);
CREATE TABLE tab_uwagi (
id_zamowienia integer NOT NULL PRIMARY KEY,
uwagi character varying(400) NOT NULL
);
CREATE TABLE tab_zamowienia_archiwum (
id_zamowienia integer NOT NULL PRIMARY KEY,
id_pracownika integer NOT NULL REFERENCES tab_pracownicy(id_pracownika)
ON UPDATE RESTRICT,
id_przedstawiciela integer NOT NULL REFERENCES
tab_przedstawiciele_kontrahenta(id_przedstawiciela) ON UPDATE RESTRICT,
data_zamowienia timestamp without time zone NOT NULL
);
CREATE TABLE tab_data_wyslania (
id_zamowienia integer NOT NULL PRIMARY KEY
REFERENCES tab_zamowienia_archiwum(id_zamowienia) ON UPDATE RESTRICT,
id_produktu integer NOT NULL REFERENCES tab_produkty(id_produktu)
ON UPDATE RESTRICT,
ilosc integer NOT NULL,
cena double precision NOT NULL,
data_wyslania timestamp without time zone NOT NULL
);
CREATE SEQUENCE tab_faktury_vat_id_faktury_seq
START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1;
CREATE TABLE tab_faktury_vat (
id_faktury integer NOT NULL DEFAULT nextval('tab_faktury_vat_id_faktury_seq')
PRIMARY KEY,
id_zamowienia integer NOT NULL
REFERENCES tab_zamowienia_archiwum(id_zamowienia) ON UPDATE RESTRICT,
data_wystawienia_faktury timestamp without time zone NOT NULL
);
2. Słownik danych
W projekcie użyto dwóch słowników danych: tab_typy_statusu, określający status pracownika oraz tab_typy_rabatu, określający rodzaj przyznanego rabatu. Przykład wypełnienia słowników prezentują tabele 1 i 2:
id_rabatu | opis |
1 | Upust jednostkowy |
2 | Upust procentowy |
3 | Upust kwotowy |
Tablica 1: tab_typy_rabatu
id_statusu | opis |
1 | Administrator |
2 | Sprzedawca |
3 | Magazynier ? |
4 | Pracownik działu produkcji |
Tablica 2: tab_typy_statusu
3. Analiza zależności funkcyjnych i normalizacja tabel
Tabele spełniaja założenia normalizacji.
Wątpliwości budzi tab_produkcja. Wydawać by się mogło, że należałoby utworzyć dodatkowy słownik danych np. tab_postep_produkcji, jednak po głębszej analizie dochodzimy do wniosku, że postępy produkcji są atrybutami, których przestrzeń jest zbyt duża, aby wszystkie zapamiętać w tabeli. Za pewne, często wystąpi atrybut „nie rozpoczęto”, „w trakcie” albo „zrealizowano”, jednakże zachodzi potrzeba użycia atrybutów innych, np. „odłożono do przyszłego tygodnia”, „przerwa z powodu braku materiałów”, itp.
4. Denormalizacja struktury tabel
W celu optymalizacji przechowywania danych, wydzielono tabele:
tab_uwagi,
tab_opis,
tab_polozenia,
tab_produkcja.
oraz tabele przeznaczone stricte na archiwum danych:
tab_zamowienia_archiwum,
tab_faktury_vat,
tab_data_wyslania.
5. Zdefiniowanie kwerend dla realizacji funkcji wyspecyfikowanych w projekcie
1.1.3. Wyświetlanie spisu zamówień
select k.nazwa, z.data_zamowienia, pk.nazwisko || ' ' || pk.imie,
p.nazwisko || ' ' || p.imie, z.id_zamowienia
from tab_kontrahenci as k, tab_zamowienie as z,
tab_przedstawiciele_kontrahenta as pk, tab_pracownicy as p
where z.id_kontrahenta = k.id_kontrahenta and
pk.id_przedstawiciela = z.id_przedstawiciela and
p.id_pracownika = z.id_pracownika and
z.id_zamowienia not in (select id_zamowienia from tab_zamowienia_archiwum)
5.2. Podgląd statystyk (porównanie przychodów z produktów)
select p.nazwa, sum(sz.ilosc*p.cena_netto)
from tab_spis_zamowien sz inner join tab_produkty p on p.id_produktu = sz.id_produktu
where (select z.data_zamowienia from tab_zamowienie z
where sz.id_zamowienia = z.id_zamowienia)
between ? and ?
group by p.nazwa"
5.1 Podgląd raportów (pracownik miesiąca)
select p.imie || ' ' || p.nazwisko as nazw, count(z.id_pracownika) as cnt
from tab_zamowienie z inner join tab_pracownicy p on p.id_pracownika = z.id_pracownika
where data_zamowienia BETWEEN ? AND ?
group by nazw
order by cnt desc
1.4.2 Edycja danych kontrahenta
select imie, nazwisko, telefon, email, opis
from tab_przedstawiciele_kontrahenta
where id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy');
update tab_przedstawiciele_kontrahenta set (imie, nazwisko, telefon, email, opis) =
('kazek', 'nowy','1234567890', 'asd@asd.pl','asdfg')
where imie = 'Dwa' and id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy')
select email, opis
from tab_email_kontrahenta
where id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy');
update tab_email_kontrahenta set ( email, opis) = ( 'asd@asd.pl','asdfg')
where email = 'nowy1@email.pl' and id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy')
select telefon, opis
from tab_telefon_kontrahenta
where id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy');
update tab_telefon_kontrahenta set ( telefon, opis) = ( '1234567890','asdfg')
where telefon = '100100100' and id_kontrahenta =
(select id_kontrahenta from tab_kontrahenci where nazwa = 'nowy')
select nazwa, nip, miasto, ulica, nr_domu, kod_pocztowy
from tab_kontrahenci
where nazwa = 'kont1'
update tab_kontrahenci set (nazwa, nip, miasto, ulica, nr_domu, kod_pocztowy) =
('nowy', '1234567890','krak', 'dluga','123a','01234')
where nazwa = 'kont1
Powrót do strony projektu