=====-. Projekt logiczny ===== ====-. Projekt bazy danych (SQL) ==== DROP TABLE IF EXISTS Users CASCADE; DROP TABLE IF EXISTS Categories CASCADE; DROP TABLE IF EXISTS Albums CASCADE; DROP TABLE IF EXISTS Photos CASCADE; DROP TABLE IF EXISTS TrustedUsers CASCADE; DROP TABLE IF EXISTS Comments CASCADE; DROP TABLE IF EXISTS Subscriptions CASCADE; DROP TABLE IF EXISTS Activations CASCADE; DROP TABLE IF EXISTS Votes CASCADE; CREATE TABLE Users ( user_id serial primary key, login character varying(255) NOT NULL, password character varying(255) NOT NULL, email character varying(255) NOT NULL, activation_code char(32) DEFAULT NULL, date_of_birth date DEFAULT NULL, about text DEFAULT NULL, notify_comment boolean NOT NULL, notify_photo boolean NOT NULL, notify_subscr boolean NOT NULL ); CREATE TABLE Categories ( category_id serial primary key, name varchar(255) NOT NULL ); CREATE TABLE Albums ( album_id serial primary key, user_id integer NOT NULL REFERENCES Users, category_id integer NOT NULL REFERENCES Categories, name varchar(255) NOT NULL, description text, rating smallint, views integer default 0, next_notification timestamp, public boolean NOT NULL, password varchar(255), comments_allow boolean NOT NULL, comments_auth boolean NOT NULL, notification_period integer ); CREATE INDEX album_user_idx on Albums (user_id); CREATE INDEX album_cat_idx on Albums (category_id); CREATE INDEX album_rat_idx on Albums (rating); CREATE TABLE Photos ( photo_id serial primary key, album_id integer NOT NULL REFERENCES Albums, date_taken timestamp NOT NULL, description text, file_path text NOT NULL, --location geography(point,4326) loc_latitude numeric(10,7) CHECK (loc_latitude >= -90 AND loc_latitude <= 90), loc_longitude numeric(10,7) CHECK (loc_longitude >= -180 AND loc_longitude <= 180) ); CREATE INDEX photo_album_idx on Photos (album_id); CREATE INDEX photo_date_idx on Photos(date_taken); CREATE TABLE TrustedUsers ( album_id integer REFERENCES Albums, user_id integer REFERENCES Users, primary key(user_id, album_id) ); CREATE TABLE Comments ( comment_id serial primary key, album_id integer NOT NULL REFERENCES Albums, user_id integer NOT NULL REFERENCES Users, date_posted timestamp NOT NULL, "body" varchar(1000) NOT NULL, accepted boolean NOT NULL, ); CREATE INDEX comment_user_idx on Comments (user_id); CREATE INDEX comment_album_idx on Comments (album_id); CREATE TABLE Subscriptions ( user_id integer REFERENCES Users, album_id integer REFERENCES Albums, primary key(user_id, album_id) ); CREATE TABLE Votes ( user_id integer REFERENCES Users, album_id integer REFERENCES Albums, primary key(user_id, album_id), up boolean NOT NULL ); CREATE INDEX vote_album_idx on Votes (album_id); ====-. Słowniki danych ==== * User - tabela przechowująca dane na temat użytkowników aplikacji user_id, INT SERIAL PRIMARY KEY - klucz główny, unikalne ID użytkownika\\ login, varchar(255) NOT NULL - login użytkownika w serwisie\\ password, varchar(255) NOT NULL - hasło zahashowane\\ email, varchar(255) NOT NULL - adres email użytkownika\\ active, boolean NOT NULL - czy konto jest aktywne\\ date_of_birth, date - data urodzenia\\ about, TEXT - informacje dodatkowe u użytkowniku\\ notify_comment, boolean - czy użytkownik ma być powiadamiany mailowo o komentarzach\\ notify_photo, boolean - czy wysyłane jest przypomnienie o zrobieniu nowego zdjęcia\\ notify_subscr, boolean - czy użytkownik ma być powiadamiany mailowo o nowych zdjęciach w obserwowanych albumach\\ notification_period, smallint - ilość dni, co jaką wysyłane jest w/w przypomnienie o zrobieniu zdjęcia\\ * Album - tabela przechowująca dane na temat albumów ze zdjęciami album_id, INT SERIAL PRIMARY KEY - klucz główny, unikalne ID albumu\\ user_id, INT NOT NULL - klucz obcy do tabeli User, oznacza właściciela albumu\\ category_id, INT NOT NULL - klucz obcy do tabeli Category, oznacza kategorię, do której należy album\\ name, varchar(255) NOT NULL - nazwa albumu\\ description, text - opis albumu\\ rating, smallint - ocena albumu (wyrażona w skali 1-10)\\ views, integer - liczba odsłon albumu\\ next_notification, timestamp - kiedy ma być wysłane najbliższe powiadomienie do użytkownika o konieczności zrobienia zdjęcia do albumu\\ public, boolean NOT NULL - czy album jest publiczny, czy widoczny tylko dla użytkownika\\ password, varchar(255) NOT NULL - hasło zahashowane\\ comments_allow, boolean NOT NULL - czy możliwe jest dodawanie komentarzy do albumu\\ comments_auth, boolean NOT NULL - czy komentarze wymagają moderacji autora\\ * Category- tabela przechowująca dane na temat kategorii dla albumów category_id, INT SERIAL PRIMARY KEY - klucz główny, unikalne ID kategorii\\ name, varchar(255) NOT NULL - nazwa kategorii\\ * Photo - tabela przechowująca dane na temat fotografii photo_id, INT SERIAL PRIMARY KEY - klucz główny, unikalne ID fotografii\\ album_id, INT NOT NULL - klucz obcy do tabeli Album, oznacza album do którego należy zdjęcie\\ date_taken, timestamp NOT NULL - data zrobienia zdjęcia\\ description, text - opis zdjęcia\\ file_path, text NOT NULL - scieżka do pliku ze zdjęciem\\ loc_latitude, numeric(10,7) - szerokość geograficzna, na której zostało zrobione zdjęcie\\ loc_longitude, numeric(10,7) - długość geograficzna, na której zostało zrobione zdjęcie * TrustedUser - tabela łącznikowa przechowująca zaufanych użytkowników powiązanych z albumami album_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli Album, określa album do którego dostęp ma użytkownik\\ user_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli User, określa użytkownika, który ma dostęp do albumu\\ * Subscription - tabela łącznikowa przechowująca informacje o subskrypcji albumów przez użytkowników album_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli Album, określa subskrybowany album\\ user_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli User, określa użytkownika, który subskrybuje album\\ * Comment - tabela przechowująca dane na temat komentarzy comment_id, INT SERIAL PRIMARY KEY - klucz główny, unikalne ID komentarza\\ album_id, INT NOT NULL - klucz obcy do tabeli Album, oznacza album do którego należy komentarz\\ user_id, INT NOT NULL - klucz obcy do tabeli User, oznacza autora komentarza\\ date_posted, timestamp NOT NULL - data opublikowania komentarza\\ body, varchar(1000) NOT NULL - treść komentarza\\ accepted, boolean NOT NULL - czy komentarz został zaakceptowany i może być wyświetlony * Votes - tabela łącznikowa przechowująca informacje o głosach oddanych na albumy \\ album_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli Album, określa na który album został oddany głos\\ user_id, INT PRIMARY KEY - klucz główny, klucz obcy do tabeli User, określa użytkownika, który głosował na album\\ up, boolean NOT NULL - określa czy głos był pozytywny (true) czy negatywny (false) ====-. Analiza zależności funkcyjnych i normalizacja tabel ==== * **1NF - pierwsza postać normalna** //__Warunki__//\\ Tabele w bazie spełniają warunek pierwszej postaci normalnej, jeśli każda z tych tabel spełnia następujące warunki:\\ -opisuje jeden obiekt,\\ -wartości atrybutów są elementarne (atomowe, niepodzielne) - każda kolumna jest wartością skalarną (atomową), a nie macierzą lub listą czy też czymkolwiek, co posiada własną strukturę,\\ -nie zawiera kolekcji (powtarzających się grup informacji),\\ -posiada klucz główny,\\ -kolejność wierszy może być dowolna (znaczenie danych nie zależy od kolejności wierszy).\\ //__Analiza bazy danych__//\\ Baza jest w pierwszej postaci formalnej, gdyż spełnia w/w warunki. * **2NF - druga postać normalna** //__Warunki__//\\ Baza jest w drugiej postaci normalnej, wtedy gdy spełniona jest 1NF oraz gdy wartości nie-kluczowe są zależne od klucza głównego.\\ //__Analiza bazy danych__//\\ Następujące tabele posiadają klucz prosty, więc ich atrybuty zależą od całego klucza głównego:\\ User\\ Album\\ Photo\\ Comment\\ Category\\ Następujące tabele mają klucze złożone:\\ Subscription\\ TrustedUser\\ Tabele te nie posiadają atrybutów niekluczowych. Baza jest w 2NF. * **3NF - trzecia postać normalna** //__Warunki__//\\ Baza jest w trzeciej postaci normalnej, gdy spełniona jest 2NF oraz gdy wszystkie wartości niekluczowe zależą bezpośrednio od wartości klucza głównego. //__Analiza bazy danych__//\\ Wartości niekluczowe we wszystkich tabelach zależą bezpośrednio od wartości klucza głównego.\\ Zależności przechodnie (transitive dependencies), które łamią tę zasadę, zostały wyeliminowane poprzez rozbicie danych na osobne tabele. \\ Przykład: \\ Gdyby w tabeli 'Album' było pole z nazwą kolekcji, tabela nie spełniałaby 3NF. Dzięki stworzeniu osobnej tabeli z kolekcjami i umieszczeniu do niej odwołania w tabeli 'Album', tabela spełnia 3NF. ====-. Projektowanie operacji na danych ==== * Logowanie użytkownika SELECT `User`.* FROM `User` WHERE (login='Wacek') AND (password='#PasswordHash#'); * Rejestracja użytkownika insert into User(login, email, password, active) values('Wacek', 'wacek@amorki.pl', '#password_hash#', false); * Aktualizacja profilu użytkownika update User set about = 'moja historia', notify_subscr = true where User.id = 11;