====== Projekt logiczny ====== ===== 1. Projekt tabel ===== We wszystkich tabelach konsekwentnie użyliśmy //ID// jako klucza głównego. Klucze obce mają jasną nazwę odpowiadającą tabeli na którą wskazują, np. //IDGrupy// - tabela GrupyWynikowe. Jedynymi indeksami są klucze tabel. Tabele: * **OpisProblemu** - Tabela powstała w celu umożliwienia jednoczesnej pracy z aplikacją. "Problem" reprezentuje jedną instancję programu, która jest jednoznacznie identyfikowana. Kolumna //CSV// typu text zawiera plik CSV podany na wejście, w celu ewentualnego odtworzenia danych, weryfikacji itp. * **DaneBazowe** - Podstawowe informacje zaimportowane z pliku CSV: //Miasto//, //Ulica// - kolumny typu varchar o długości nie większej niż 200 znaków. //X//, //Y//, //Z// - kolumny typu double precision reprezentujące współrzędne. Klucze obce: //IDProblemu// -> OpisProblemu.ID * **GrupyWynikowe** - Rezultat działania algorytmu. Jedyna kolumna //ID// jednoznacznie identyfikuje grupę, do której można przypisać punkty. Grupę tworzą współliniowe punkty znajdujące się w danej odległości od siebie z pewną dokładnością. * **PasyTymczasowe** - Zawiera informacje o kącie nachylenia (kolumna //kat//) oraz dlugości pasa (kolumna //dlugosc//), które to informacje są wykorzystywane w kolejnych iteracjach algorytmu. "Pas" to podłużny prostokąt w skład którego wchodzą punkty. Jest to pomocne przy poszukiwaniu punktów współliniowych. * **DaneGeograficzne** - Tabela przechowująca informacje PostGISa o punkcie. 2 kolumny: punkt2d i punkt3d reprezentują odpowiednio dwu- i trzywymiarowe punkty, które są wykorzystywane podczas działania algorytmu. Klucze obce: //ID// -> DaneBazowe.ID * **Parametry** - Zawiera nazwy parametrów dodatkowych przekazanych na wejście. Dzięki tej tabeli każdemu punktowi można przypisać dowolną wartość parametru dodatkowego. Tabele połączeniowe: * **Grupy_Punkty** - Punkty z tabeli DaneBazowe przypisane do danej grupy z tabeli GrupyWynikowe * **Pasy_Punkty** - Punkty z tabeli DaneBazowe przypisane do danego pasu z tabeli PasyTymczasowe * **DaneBazowe_Parametry** - Parametry wraz z wartością odpowiadające punktom z tabeli DaneBazowe ===== 2. Diagram ERD przedstawiający schematy tabel ===== {{:pl:dydaktyka:sbd:2012:projekty:oswietlenie:start:oracle.png|}} ===== 3. Tablica krzyżowa ===== {{:pl:dydaktyka:sbd:2012:projekty:oswietlenie:start:tablica_krzyzowa_2.png|}} * T1 - OpisProblemu * T2 - DaneBazowe * T3 - GrupyWynikowe * T4 - PasyTymczasowe * T5 - Grupy_Punkty * T6 - Pasy_Punkty * T7 - DaneGeograficzne * T8 - Parametry * T9 - DaneBazowe_Parametry ===== 4. Projekt bazy w języku SQL ===== create sequence OpisProblemu_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table OpisProblemu( ID integer default nextval('OpisProblemu_ID_seq') primary key, CSV text not null ); create sequence DaneBazowe_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table DaneBazowe( ID integer default nextval('DaneBazowe_ID_seq') primary key, IDProblemu integer not null references OpisProblemu (ID), Miasto varchar(200) not null, Ulica varchar(200) not null, X double precision not null, Y double precision not null, Z double precision not null ); create sequence GrupyWynikowe_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table GrupyWynikowe( ID integer default nextval('GrupyWynikowe_ID_seq') primary key ); create sequence PasyTymczasowe_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table PasyTymczasowe( ID integer default nextval('PasyTymczasowe_ID_seq') primary key, Kat double precision not null, Dlugosc double precision ); create sequence Grupy_Punkty_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table Grupy_Punkty( ID integer default nextval('Grupy_Punkty_ID_seq') primary key, IDGrupy integer not null references GrupyWynikowe (ID), IDPunktu integer not null references DaneBazowe (ID), Kolejnosc integer not null ); create sequence Pasy_Punkty_ID_seq start with 1 increment by 1 no maxvalue no minvalue cache 1; create table Pasy_Punkty( ID integer default nextval('Pasy_Punkty_ID_seq') primary key, IDPasa integer not null references PasyTymczasowe (ID), IDPunktu integer not null references DaneBazowe (ID) ); create table DaneGeograficzne( ID integer references DaneBazowe (ID) ); -- geometria 3-wymiarowa select AddGeometryColumn('danegeograficzne', 'punkt2d', 4326, 'POINT', 2); select AddGeometryColumn('danegeograficzne', 'punkt3d', 4326, 'POINT', 3); create table Parametry( ID serial primary key, Nazwa text not null ); create table DaneBazowe_Parametry( IDPunktu integer not null references DaneBazowe (ID), IDParametru serial references Parametry (ID), Wartosc text ); ===== 5. Słowniki danych ===== DowolneZnaki = *wszystkie znaki dla przyjętego standardu kodowania* ID = *zakres: od 1 do końca zakresu typu integer* * **OpisProblemu** OpisProblemu = ID + CSV CSV = *dane wejściowe pobierane z pliku w formacie CSV* {DowolneZnaki} * **DaneBazowe** DaneBazowe = ID + IDProblemu + Miasto + Ulica + X + Y + Z IDProblemu = *zakres: pełny zakres typu integer* {OpisProblemu} ZnakiDlaMiasta = [A-Z|a-z|-| |] Miasto = *zakres: 1-200 znaków* {ZnakiDlaMiasta} ZnakiDlaUlicy = [A-Z|a-z|-|.| |] Ulica = *zakres: 1-200 znaków* {ZnakiDlaUlicy} X = *współrzędna; zakres: pełny zakres typu double* Y = *współrzędna; zakres: pełny zakres typu double* Z = *współrzędna; zakres: pełny zakres typu double* * **GrupyWynikowe** GrupyWynikowe = ID * **PasyTymczasowe** PasyTymczasowe = ID + Kat + (Dlugosc) Kat = *kąt obrotu pasa względem osi OX; jednostka: radiany; zakres: -π/2 do π/2* Dlugosc = *kąt obrotu pasa względem osi OX; jednostka: stopnie; zakres: -180 do 180* * **Grupy_Punkty** Grupy_Punkty = ID + IDGrupy + IDPunktu + Kolejnosc IDGrupy = *odnosi się do GrupyWynikowe; zakres: od 1 do końca zakresu typu integer* IDPunktu = *odnosi się do DaneBazowe; zakres: od 1 do końca zakresu typu integer* Kolejnosc = *zakres: pełny zakres typu integer* * **Pasy_Punkty** Pasy_Punkty = ID + IDPasa + IDPunktu IDPasa = *odnosi się do PasyTymczasowe; zakres: od 1 do końca zakresu typu integer* IDPunktu = *odnosi się do DaneBazowe; zakres: od 1 do końca zakresu typu integer* * **DaneGeograficzne** DaneGeograficzne = ID ID = *odnosi się do DaneBazowe; zakres: od 1 do końca zakresu typu integer* * **Parametry** Parametry = ID + Nazwa ZnakiDlaNazwy = [A-Z|a-z|-|_|0-9|] Nazwa = *zakres: nieograniczony łańuch znaków* {ZnakiDlaNazwy} * **DaneBazowe_Parametry** DaneBazowe_Parametry = ID + IDPunktu + IDParametru IDPunktu = *odnosi się do DaneBazowe; zakres: od 1 do końca zakresu typu integer* IDParametru = *odnosi się do Parametry; zakres: od 1 do końca zakresu typu integer* ===== 6. Analiza zależności funkcyjnych i normalizacja tabel ===== * **OpisProblemu** * IDOpisProblemu * IDOpisProblemu -> CSV * **Adres** * IDAdres * IDAdres -> Miasto * IDAdres -> Ulica * **Wspolrzedne** * IDWspolrzedne * IDWspolrzedne -> X * IDWspolrzedne -> Y * IDWspolrzedne -> Z * IDWspolrzedne -> punkt2d * IDWspolrzedne -> punkt3d * **Parametr** * IDParametr * IDParametr -> Nazwa * **Parametr_Wartosc** * IDParametr_Wartosc * IDParametr * IDParametr -> Wartosc * **Latarnia** * IDLatarnia * IDLatarnia -> IDAdres * IDLatarnia -> IDWspolrzedne * IDLatarnia -> IDParametr_Wartosc * **OpisProblemu_Latarnia** * IDOpisProblemu * IDLatarnia ===== 7. Opcjonalnie: Denormalizacja struktury tabel ===== ===== 8. Projektowanie operacji na danych ===== Listowanie wszystkich punktów dla danego problemu: SELECT ID, Miasto, Ulica, X, Y, Z FROM DaneBazowe WHERE IDProblemu=%id_problemu%; Tworzenie wierszy w tabeli z danymi i tabeli geograficznej (SRID = 4326): INSERT INTO DaneBazowe (IDProblemu, Miasto, Ulica, X, Y, Z) VALUES(%idproblemu%, %miasto%, %ulica%, %x%, %u%, %z%)) RETURNING ID, X, Y; -- potrzebne dla tabeli geograficznej INSERT INTO DaneGeograficzne (ID, punk2d, punkt3d) VALUES (%id%, ST_SetSRID(ST_MakePoint(%x%, %y%), 4326), ST_SetSRID(ST_MakePoint(%x%, %y%, %z%), 4326)); Pobieranie współrzędnych z tabeli geograficznej: SELECT ST_X(punkt2d), ST_Y(punkt2d) FROM DaneGeograficzne JOIN DaneBazowe on DaneBazowe.ID = DaneGeograficzne.ID WHERE DaneBazowe.IDProblemu = %id_problemu%; Pobierz punkty leżące w pasie pomiędzy punktami (2, 3) a (11, 3) o szerokości 2: SELECT ST_X(punkt2d) as X, ST_Y(punkt2d) as Y FROM (SELECT punkt2d, ST_Buffer(ST_GeomFromText('LINESTRING(2 3, 11 3)', 4326), 2, 'endcap=round') as Pas FROM DaneGeograficzne JOIN DaneBazowe on DaneGeograficzne.ID = DaneBazowe.ID WHERE IDProblemu = %id_problemu% ) as Temp WHERE ST_Within(punkt2d, Pas); Znajdź punkty znajdujące się w odległości w zakresie (1, 3) od punktu o ID = 987: SELECT ST_X(Punkt.p1) as p1x, ST_Y(Punkt.p1) as p1y, ST_X(Punkty.p2) as p2x, ST_Y(Punkty.p2) as p2y, ST_Distance(p1, p2) as dist FROM ( SELECT punkt2d as p1 FROM DaneGeograficzne WHERE ID = 987 ) as Punkt, ( SELECT punkt2d as p2 FROM DaneGeograficzne JOIN DaneBazowe on DaneGeograficzne.ID = DaneBazowe.ID ) as Punkty WHERE ST_Distance(p1, p2) > 1 AND ST_Distance(p1, p2) < 3; Usuwanie wszystkich danych powiązanych z danym problemem: delete from DaneGeograficzne where ID in ( select ID from DaneBazowe where IDProblemu=%problemid% ); delete from Grupy_Punkty where IDPunktu in ( select ID from DaneBazowe where IDProblemu=%problemid% ); delete from Pasy_Punkty where IDPunktu in ( select ID from DaneBazowe where IDProblemu=%problemid% ); delete from DaneBazowe_parametry where IDPunktu in ( select ID from DaneBazowe where IDProblemu=%problemid% ); delete from DaneBazowe where IDProblemu=%problemid%; delete from OpisProblemu where ID=%problemid%;