Relacyjne Bazy Danych Wojciech St. Mościbrodzki wojmos@wojmos.com
Plan przedmiotu BAZY DANYCH – edycja 2018 zaoczne prowadzący: zajęcia 1-8: Wojciech Mościbrodzki wykład: część teoretyczna zaliczenie w postaci egzaminu (WM) laboratorium praktyka baz danych projekt literatura: R. Elmasari, S. B. Navathe, Wprowadzenie do systemów baz danych, Helion, 2005 R. Stones, N.Matthew, Bazy danych i PostgreSQL, Helion, 2002 (seria Wrox) Jeffrey D. Ullman, Jennifer Widom, Podstawowy wykład z systemów baz danych, WNT, 2001 (seria Klasyka Informatyki) S. Sumathi, S. Esakkirajan Fundamentals of Relational Database Management Systems www.mysql.com
Zagadnienia wstępne
Krótkie wprowadzenie do teorii i praktyki danych DANE = to wszystko co jest/może być przetwarzane BAZA DANYCH pierwsze użycie pojęcia - 1963 zbiór danych (niekoniecznie w postaci elektronicznej) program do przetwarzania i zarządzania danymi (DBMS=SZBD) jeden ze zbiorów danych zarządzanych przez DBMS Funkcje DBMS: zarządzanie danymi (dodawanie, usuwanie, modyfikacja) wyszukiwanie danych i informacji zarządzanie bazami danych zarządzenie bezpieczeństwem, wydajnością i awariami
Modele danych MODELE DANYCH plikowy sieciowy (kolejki i złożone struktury składające się na kolejki) hierarchiczny (pliki, rekordy, związki nadrzędny-podrzędny) relacyjny obiektowy strumieniowy XML
Bazy danych, bazy wiedzy Struktury informacji dane metadane wiedza inteligencja? Wyzwania gromadzenie zarządzanie przetwarzanie wnioskowanie rozumienie wymyślanie
Systemy ekspertowe System ekspercki: jawna reprezentacja wiedzy oddzielenie wiedzy eksperckiej od procedur sterowania zdolność do wyjaśnień (ang. explanation facilities), w szczególności sposobu rozwiązania danego problemu rozwiązanie powstaje z wykorzystaniem różnych metod wnioskowania przetwarzanie symboli zamiast typowych obliczeń numerycznych
Serwery baz danych (baz komputerowych) infrastruktura sprzętowa bazy danych oprogramowanie SZBD Konfiguracja typowa: Serwer = {baza1, baza2, ... bazaN} Komputer = {serwer1, serwer2, ... serwerN} Model klastra serwerów baz relacyjnych: Kluster = {serwer1, serwer2, serwer3... serwer N} serwer1 = {baza1, baza2, baza3, ... bazaM} baza1 = {encja1, encja2, ... encja3, ....relacja1, relacja2, ...}
Bazy danych – SZBD, serwer, architektury Architektury plikowe, serwerowe i klastrowe
Typowa architektura MySQL
Konfiguracja dostępu do MySQL Pośród poleceń, które będziemy wykonywać można wyróżnić: Standardowe rozkazy SQL Dialekt SQL, zależny od serwera Polecenia klienta i serwera, wychodzące poza SQL
Pierwsze podsumowanie Dane i zbiory danych Model danych System bazy danych = dane + system zarządzania Serwery baz danych
RELACYJNY MODEL DANYCH
Encje Encja – pojęcie pierwotne; niepowtarzalny, unikalny byt Szerzej: rodzaj reprezentacji grupy obiektów opisywanych przez takie same własności; rodzaj nowotworzonego „typu” (analogia do języków programowania). POPRAWNIEJ: ENCJA-TYP PRZYJMUJE SIĘ JEDNAK: ENCJA = ENCJA-TYP Tradycyjnie, nazwy encji oznaczamy liczbą pojedynczą (CZŁOWIEK, a nie: LUDZIE) Przykład: encja SAMOCHÓD (przedmioty posiadajace kolor i tablicę rejestracyjną) Dwa fizyczne przedmioty mogą należeć do tej samej encji lub nie (zależnie od założeń, definicji) np. dwóch ludzi rozróżnianych tylko po PESEL – tak Człowiek-pracownik firmy i człowiek-obcokrajowiec - nie
Encje Atrybut encji – jedna z jej własności; przyjmuje się, że atrybuty mają określony pewien zakres dopuszczalnych wartości Encja jest pewną abstrakcją, modelem, logiczną reprezentacją rzeczywistości – wygodnie o niej myśleć jak o tablicy o ustalonej strukturze („miejsce na atrybuty”) lub o zbiorze obiektów SAMOCHÓD NrRej Kolor RokProd
Możliwe są następujące przypadki: Relacje i krotności Relacja (ściślej: relacja binarna), to związek, w którym pozostają ze sobą dwie encje (ich elementy). Możliwe są następujące przypadki: Jednemu elementowi encji A odpowiada kilka elementów encji B, ale każdemu elementowi B odpowiada jeden (lub zero) elementów encji A Jednemu elementowi encji A odpowiada kilka elementów encji B, a każdemu elementowi B odpowiada kilka (lub zero) elementów encji A Jednemu elementowi encji A odpowiada jeden (lub zero) element encji B, a UWAGA: jeśli element encji nie pozostaje w relacji, to nie „psuje” to krotności. Czasami wyraźnie oznaczamy to nazwą np. „relacja 1-do-1 z opcją 0”
Relacja jeden-do-jeden Przykład: CZŁOWIEK i PASZPORT CZŁOWIEK PASZPORT relacja 1-do-1 relacja 1-do-1 UWAGI: Każdy człowiek może mieć tylko jeden paszport Paszport może należeć tylko do jednego człowieka Są ludzie, którzy nie mają paszportów Są paszporty, które do nikogo nie należą (bo np. właściciel zmarł) Taki model nie zakłada możliwości błędu (np. podwójnie wydany dokument!)
Relacja jeden-do-wiele Przykład: CZŁOWIEK i PIES CZŁOWIEK PIES relacja 1-do- relacja 1-do- UWAGI: Każdy człowiek może być właścicielem wielu psów Jeden pies uznaje za swego pana tylko jednego człowieka Są ludzie, którzy nie mają psów Są bezpańskie psy
Relacja wiele-do-wiele Przykład: CZŁOWIEK i SAMOCHÓD CZŁOWIEK SAMOCHÓD relacja -do- relacja -do- UWAGI: Każdy człowiek może być właścicielem wielu samochodów Każdy samochód może mieć wielu właścicieli (współwłasność) Są ludzie, którzy nie mają samochodów Są bezpańskie samochody (np. zezłomowane, porzucone, nieznany właściciel)
ERD Diagram związków encji (ERD) to podstawowe narzędzie modelowania danych Składa się z ENCJI (wraz z ATRYBUTAMI) i RELACJI pomiędzy nimi zachodzących Istnieją (niestety) różne sposoby zapisu encji i relacji, klasycznie: ENCJA Atrybut Relacja
Klasyczny ERD Zapis klasyczny: ENCJA Ma CZŁOWIEK ENCJA Ma CZŁOWIEK NrRej Kolor PESEL Zapis klasyczny i uproszczony (bez nazw relacji): ENCJA CZŁOWIEK NrRej Kolor PESEL
Inny przykład
Notacja UML
Notacja w jednym z narzędzi
Notacja rozszerzona EERD Notacja rozszerzona wprowadzona została głównie dla możliwości pokazywania „zawierania się” encji w sobie
Klucze Z pojęciem ENCJI wiąże się pojęcie KLUCZA (key), czyli takiego zestawu atrybutów, których wartości są unikalne w obrębie encji. Klucze mogą być proste (jeden atrybut) lub złożone (wiele atrybutów). Od klucza wymaga się, by był możliwie mały – to znaczy, że usunięcie jednego z atrybutów sprawia, że pozostałe nie stanowią klucza. Każda encja może mieć kilka kluczy kandydujących (to jest zestawów atrybutów, które mogą być kluczami), z których wybierany jest klucz główny.
Istnieje kilka kluczy kandydujących – prostych i złożonych Klucze Istnieje kilka kluczy kandydujących – prostych i złożonych Pytanie: czy PESEL jest dobrym kluczem w bazie danych ludzi? Teoretyk: TAK! Praktyk: NIE!
Dane logiczne i dane fizyczne Od początku istnienia „nowożytnych” baz danych informacje przechowywano w tabelach. ENCJA TABELA BAZY DANYCH ATRYBUT KOLUMNA ELEMENT ENCJI KROTKA / REKORD RELACJA TABELA BAZY DANYCH Relacyjne bazy danych są w rzeczywistości zarządzalnymi zbiorami tabel, na których wykonywane są proste operacje Językiem porozumiewania się z bazą danych jest SQL Polecenia SQL to ZAPYTANIA (a nie: kwerendy!!!)
Encje - przypomnienie Encja i encja-typ Przykłady: każda unikalna (identyfikowalna) rzecz posiada atrybuty (cechy) przyjmujące określone wartości zbiór wartości atrybutu, nazywamy dziedziną encja (ściślej: encja-typ) to zbiór wszystkich encji identyfikowalnych przez ten sam zbiór atrybutów Przykłady: Jan Kowalski = encja cechy (atrybuty) Jana Kowalskiego = {wzrost, kolor oczu, imię, nazwisko} wartości atrybutów Jana Kowalskiego = {174, zielony, Jan, Kowalski} student (np. Jan Kowalski) = encja (ściślej: encja-typ) atrybut encji student: kolor oczu wartości atrybutu kolor oczu (dziedzina atrybutu) = {zielony, piwny, niebieski}
Encja - identyfikowalność klucz kandydujący nieformalnie: atrybuty, których wartości identyfikują encje formalnie: to każdy zbiór atrybutów, który posiada dwie własności: wartości atrybutów są różne dla każdej encji usunięcie dowolnego atrybutu ze zbioru, sprawia, że warunek powyżej nie jest spełniony klucz główny wybrany (arbitralnie) jeden z kluczy kandydujących Klucze kandydujące: {imię}, {semestr, miasto}, {semestr, wiek} itd.
Diagram Związków Encji (ERD) ERD służy do modelowania danych i związków pomiędzy nimi klucz zew. ENCJA atrybut klucz wyliczony Formalnie – na diagramach ER NIE OZNACZAMY TYPÓW DANYCH encja klucz główny atrybut
Diagram Związków Encji (ERD) - RELACJE ERD służy do modelowania danych i związków pomiędzy nimi różne notacje (różni autorzy) struktura pól krotność relacji Klasyczna Krucza Stopka Notacja Chena 1 1 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 1 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 N 1 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 N N ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 Notacja J. Martina Notacja Barkera ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2
Diagram Związków Encji (ERD) – przypadki szczególne Encja słaba encja słaba to taka encja, która nie jest rozróżnialna (identyfikowalna) przez własne atrybuty (wymaga klucza zewnętrznego) nagłówek faktury linia faktury numer data towar ilość Asocjacja (encja asocjacyjna, relacja wiele-do-wiele) asocjacja to relacja wiele-do-wiele (posiada cechy encji, może mieć atrybuty) w bazie danych odpowiada jej osobna tabela, zwana tabelą pośredniczącą) ENCJA 1 ENCJA2 ENCJA 1 ENCJA2 ENCJA 1 ENCJA2
Klasyfikacja relacji Kryterium krotności (dla relacji binarnych): jeden-do-jeden jeden-do-wiele wiele-do-wiele Kryterium "-narności" unarne binarne trynarne większe
Model logiczny danych (ERD) a model fizyczny zawiera informacje o encjach i relacjach nie zawiera informacji o typach danych (np. na poziomie SQL) jest niezależny od bazy danych Model fizyczny: zawiera informacje o encjach, relacjach i typach określa typy danych jest związany z implementacją
Podstawy SQL
Programowanie w SQL SQL nie jest językiem programowania – jest językiem zapytań SEQEL System R (IBM) RDMS (MIT) quel Ingres (Berkley) '70s SQL Oracle (Oracle) SQL-86 (standard ANSI): w kierunku wieloplatformowości '87 SQL-92: kursory, ALTER, DATA, TIMESTAMP, VARCHAR... '90s SQL-1999 (SQL3): triggery, BOOLEAN, control-flow (IF...) ... SQL-2003: funkcje okien danych, XML, MERGE SQL-2006: rozbudowa XML, funkcje WWW SQL-2008: INSTEAD, TRUNCATE... '00s
Programowanie z użyciem SQL Metody na "uprogramowienie" SQL: Embedded SQL (SQL osadzony): konieczny odpowiedni kompilator wartości przenoszone przez uwspólnione zmienne (widziane w SQL i w języku programowania) Modular SQL (moduły SQL dla języków programowania) konieczne są odpowiednie moduły dołączane przekazywanie wartości zależne od języka Dynamic SQL (część "programistyczna" w innym języku – np. PHP) wymaga odpowiednich konstrukcji językowych Programming Extensions for SQL (rozbudowa składni SQL – poza standardem ANSI) wymaga serwera SQL rozumiejące "rozbudowaną" składnię np. PL/SQL (Oracle), PSM (MySQL), PL PSM (PostgreSQL)
Podstawy SQL i pracy z klientem MySQL Polecenia klienta MySQL: są specyficzne dla dialektu MySQL - NIE NALEŻĄ do standardu SQL w rzeczywistości są poleceniami, które klient "tłumaczy" na zwykłe zapytania SELECT i kieruje do systemowej bazy danych mysql> show databases; +--------------------+ | Database | | information_schema | | gcs | | kardio | | mysql | | wojmos | mysql> show tables; +------------------+ | Tables_in_wojmos | | czlowiek | | faktura | mysql> explain czlowiek; +----------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | | imie | char(30) | YES | | NULL | | | nazwisko | char(50) | YES | | NULL | |
Podstawowe typy zapytań Zapytania wyszukujące dane: SELECT Zapytania modyfikujące dane: INSERT DELETE UPDATE Zapytania modyfikujące bazę danych i jej struktury: CREATE DROP ALTER GRANT / REVOKE Pseudozapytania MySQL: SHOW, EXPLAIN, DESCRIBE
CREATE DATABASE Polecenie CREATE służy do tworzenia baz: CREATE {DATABASE} [IF NOT EXISTS] db_name[create_specification] create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name W dokumentacji obowiązują następujące konwencje: {xxx} – xxx musi wystąpić xxx | yyy – musi wystąpić xxx ALBO yyy [xxx] – xxx może wystąpić (albo i nie) zzz: - wyjaśnienie symbolu zzz [ xxx | yyy ] – może wystąpić xxx ALBO yyy albo nic { xxx | yyy } – musi wystąpić xxx ALBO yyy
CREATE TABLE Polecenie CREATE TABLE służy do tworzenia tablic: CREATE TABLE {tablica} [IF NOT EXISTS] (specyfikacja) [opcje] specyfikacja: nazwa_kolumny, definicja_kolumny definicja_kolumny: typ [NULL|NOT NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] CREATE TABLE player ( ID int auto_increment primary key, name char(50) NOT NULL, dex int, str int, cha int );
Podstawowe typy danych SQL Typy danych języka SQL: numeryczne: całkowite: INT, TINYINT, SMALLINT, MEDIUMINT, BIGINT rzeczywiste: FLOAT(M,D), DOUBLE(M,D), DECIMAL(M,D) logiczne: BOOL, znakowe: łańcuchy krótkie: CHAR, VARCHAR obiekty tekstowe: TEXT daty i czasu: czasowe: DATE, TIME, DATETIME, YEAR specjalne: znacznik czasowy: TIMESTAMP obiekt binarny: BLOB wyliczeniowy: ENUM
Zapytania typu SELECT Typowy SELECT składa się z: wskazania kolumn mysql> select distinct imie from czlowiek where imie like 'jan%'; +--------+ | imie | | Jan | | Janusz | Typowy SELECT składa się z: wskazania kolumn wskazania tabeli FROM filtru rekordów WHERE warunek żądania sortowania ORDER BY select imie from czlowiek; +-------+ | imie | | Roman | mysql> select * from czlowiek; +-------+-------------+ | imie | nazwisko | | Roman | Pipokucki | | Roman | Popopizacki | mysql> select * from czlowiek order by imie DESC, nazwisko ASC; +-------+-----------+ | imie | nazwisko | | Roman | Kukurocki | | Roman | Kupikucki |
Zapytania typu INSERT Zapytania typu INSERT dodają do tablicy dane [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] {VALUES | VALUE} ({expr | DEFAULT},...),(...),... insert into player (name, dex, str, cha) values ('Raven',18,8,10); Query OK, 1 row affected (0.02 sec) insert into czlowiek values ('Jan','Nowak'); Query OK, 1 row affected (0.02 sec) Specjalna forma INSERT (SELECT AS INSERT): insert into player (name) select imie from czlowiek;
Zapytania typu UPDATE UPDATE służy do aktualizacji (modyfikacji) rekordów UWAGA1: WHERE nie jest konieczne do działania UPDATE UWAGA2: brak WHERE może przynieść opłakane skutki UPDATE table SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ... [WHERE where_condition] update player set dex=20 where name like 'Raven'; update pracownik set placa=placa+200 where name like 'Kowalski'; update pracownik set placa=placa+200 where ID=23445; update pracownik set placa=placa+200;
Polecenie ALTER służy do zarządzania strukturą ALTER TABLE tbl_name alter_specification [, alter_specification] ... alter_specification: ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name ] | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_type] | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | CHANGE [COLUMN] old_col_name new_col_name column_definition | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | DROP [COLUMN] col_name | DROP PRIMARY KEY | DROP {INDEX|KEY} | RENAME [TO] new_tbl_name | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
Relacje a tabele relacja 1-do-1 relacja 1-do-
Relacja jeden-do-wiele – realizacja w bazie danych
Podstawy SQL SQL jest językiem stosunkowo prostym (i archaicznym) Założeniem SQL była realizacja podstawowych operacji bazodanowych: wyszukiwanie rekordów - SELECT dodawanie rekordów - INSERT usuwanie rekordów - DELETE modyfikacja rekordów - UPDATE Poza „wielką czwórką” istnieją polecenia do zarządzania tabelami, bazami, tworzące indeksy, itp. Polecenia wydawane w SQL nazywamy zapytaniami SQL (a nie – kwerendami; terminologia Microsoft)
SQL jako język zapytań Typowy podział poleceń (zapytań) SQL: SQL DML (ang. Data Manipulation Language – „język manipulacji danymi”), SELECT, INSERT, UPDATE, DELETE SQL DDL (ang. Data Definition Language – „język definicji danych”), CREATE, DROP, ALTER, … SQL DCL (ang. Data Control Language – „język kontroli nad danymi”). GRANT, REVOKE, … Inny podział: polecenia standardowego (lub dialektowego) SQL (wykonuje je serwer) polecenia typowe dla serwera konkretnego producenta (wykonuje je serwer) polecenia dla klienta (oprogramowanie klienckie) – np. DELIMITER (mysql) UWAGA: średnik (;) nie jest elementem zapytania, tylko znakiem terminalnym (po jego odebraniu klient przesyła zapytanie do serwera)
Podstawy SQL Typy danych: Numeryczne (mogą być SIGNED lub UNSIGNED): Całkowite: TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT Rzeczywiste: FLOAT, DOUBLE, DECIMAL, NUMERIC Bitowe: BIT Logiczne: BOOL lub BOOLEAN (implementowane w Mysql jako TINYINT(1)) Tekstowe: CHAR – 0..255 znaków, przy przechowywaniu uzupełniane spacjami do podanego rozmiaru VARCHAR – 0..65535 znaków, zajmują długość łańcucha + informacja o dłougości (1 lub 2 bajty) BINARY i VARBINARY – przechowują łańcuchy w postaci binarnej TEXT – duży obiekt tekstowy (BLOB – wersja binarna) ENUM – typ wyliczeniowy, elementami są napisy SET – typ specjalny, może zawierać dowolną liczbę (!!!) wartości ze zbioru
Typy danych: Typy związane z czasem: DATETIME – data (domyślnie) w formacie: YYYY-MM-DD HH:MM:SS DATE – data w formacie: YYYY-MM-DD TIME – czas w formacie: HH:MM:SS Typy specjalne: BLOB – duże obiekty binarne (np. obrazki, pliki mp3) TIMESTAMP – specjalny typ (znacznik czasowy, w formacie DATETIME)
SELECT – INSERT – UPDATE - DELETE
Podstawowe formy najważniejszych zapytań SELECT – zapytanie zwracające zbiór kolumn z podanej tabeli SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] select_expr [, select_expr ...] [FROM table_references] SELECT nazwisko FROM student; SELECT imie, nazwisko FROM pracownik; SELECT DISTINCT imie FROM dostawca; SELECT COUNT(id) FROM klient; Wynikiem zapytania SELECT jest zbiór danych w postaci tabeli mysql> select * from student; +----+------------+--------+ | id | nazwisko | miasto | | 1 | Kowalski | Gdansk | | 2 | Nowak | Poznan | | 3 | Malinowski | Krakow | 3 rows in set (0.00 sec) mysql> select count(*) from user; +----------+ | count(*) | | 4 | 1 row in set (0.00 sec)
SELECT i WHERE i ORDER BY WHERE jest klauzulą filtra, nakładanego na wynik zapytania (PO wyliczeniu jego wyników) ORDER BY jest poleceniem posortowania ostatecznego rezultatu SELECT select_expr [, select_expr ...] [FROM table_references] [WHERE where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] mysql> select nazwisko from student where id<=2; +----------+ | nazwisko | | Kowalski | | Nowak | mysql> select distinct miasto from student order by miasto asc; +--------+ | miasto | | Gdansk | | Krakow |
INSERT – wstawianie rekordów INSERT – wersja klasyczna INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] {VALUES | VALUE} ({expr | DEFAULT},...),(...),... INSERT INTO student VALUES (13,'Mazan','Pruszkowo'); INSERT INTO student(nazwisko, miasto) VALUES ('Kowalewski','Warszawa'); INSERT – wersja z SET (podobna do UPDATE) INSERT [INTO] tbl_name SET col_name={expr | DEFAULT}, ... INSERT INTO student SET nazwisko='Piotrowski'; INSERT – wersja z SELECT INSERT [INTO] tbl_name [(col_name,...)] SELECT ... mysql> insert into student(nazwisko) select n from pracownik; Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0
INSERT - uwagi Wersja INSERT bez jawnego podawania kolumn wymaga, abyśmy określili wartości wszystkich istniejących w tabeli kolumn Istnieje możliwość wstawiania jednym INSERTem wielu rekordów Jeśli kolumna ma oznaczenie DEFAULT, w przypadku braku wartości w INSERT, zostanie wstawiona wartość domyślna INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
WIARYGODNOŚĆ I SPÓJNOŚĆ DANYCH
Spójność relacyjna Spójność relacyjna (relational integrity) – sytuacja, w której dane są w takiej postaci, która jest "wysokiej jakości": Spójność encji (entity integrity) – każde dwa elementy danych (obiekty) są rozróżnialne. Innymi słowy: istnieje klucz główny, a wartości tego klucza są ustalone (nie występuje NULL, czyli wartość nieustalona) Spójność wartości nieustalonych (null integrity) – dla określonych danych wartość NULL jest nieakceptowalna Spójność dziedzinowa (domain integrity) – wartości atrybutów są w dopuszczalnym zakresie (np. wiek nie może być ujemny, liczba pracowników – wyrażona ułamkiem itp.). Spójność domenowa sugeruje, że dane z różnych dziedzin nie powinny być porównywane "wprost". Spójność referencyjna (referential integrity) – odnosi się do relacji pomiędzy dwoma tabelami; wymaga aby wartości klucza obcego odpowiadały istniejącym wartościom tabeli wskazywanej (klucz główny)
Spójność referencyjna Przypomnienie: Klucz kandydujący – jeden z zestawów atrybutów, który może pełnić rolę klucza Klucz główny – wybrany arbitralnie klucz spośród kluczy kandydujących Klucz obcy – zestaw atrybutów, który odpowiada kluczowi głównemu innej tabeli
Naruszenie spójności referencyjnej Naruszenia spójności DELETE: usunięcie rekordu, do którego ID jest wartością klucza obcego UPDATE: zmiana wartości klucza obcego na nieistniejący (brak wartości klucza głównego) lub zmiana wartości klucza głównego, któremu odpowiada klucz obcy INSERT: wstawienie rekordu, którego klucz obcy odpowiada nieistniejącej wartości klucza głównego
Więzy integralności Obsługa więzów integralności w mysql (UWAGA: tylko InnoDB): [CONSTRAINT] FOREIGN KEY (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION Tabela "główna" musi istnieć podczas tworzenia tabeli "potomnej": create table dzial ( id int auto_increment primary key, nazwa char(10) ) ENGINE=InnoDB; create table pracownik ( imie char(10), nazwisko char(15), id_dzi int, CONSTRAINT FOREIGN KEY (id_dzi) REFERENCES dzial(id) Usuwanie tabel również wymaga odpowiedniej kolejności!
Spójność referencyjna Więzy typu RESTRICT (w MySQL = NO ACTION) zabraniają wykonania operacji create table pracownik ( id int auto_increment primary key, nazwisko char(15), id_dzi int, CONSTRAINT FOREIGN KEY (id_dzi) REFERENCES dzial(id) ) ENGINE=InnoDB; insert into pracownik values (1,'Jan','Nowak',1); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`rbd3/pracownik`, CONSTRAINT `pracownik_ibfk_1` FOREIGN KEY (`id_dzi`) REFERENCES `dzial` (`id`)) mysql> delete from dzial where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`rbd3/pracownik`, CONSTRAINT `pracownik_ibfk_1` FOREIGN KEY (`id_dzi`) REFERENCES `dzial` (`id`))
Spójność referencyjna Więzy typu CASCADE przenoszą operacje (DELETE lub CASCADE) z rekordów tabeli "rodzica" na tabelę "potomną" create table pracownik ( id int auto_increment primary key, nazwisko char(15), id_dzi int, CONSTRAINT FOREIGN KEY (id_dzi) REFERENCES dzial(id) ON DELETE CASCADE ) ENGINE=InnoDB; mysql> select count(id) from pracownik; delete from dzial where id=1; select count(id) from pracownik; +-----------+ | count(id) | | 4 | | 2 |
Spójność referencyjna Więzy typu SET NULL po operacji DELETE/UPDATE na rekordach tabeli "rodzica" ustawiają wartości klucza obcego na NULL create table pracownik ( id int auto_increment primary key, nazwisko char(15), id_dzi int, CONSTRAINT FOREIGN KEY (id_dzi) REFERENCES dzial(id) ON DELETE CASCADE ) ENGINE=InnoDB; select * from telefon; delete from pracownik where id=3; +----+--------+--------+ | id | serial | id_pra | | 1 | NP3451 | 1 | | 2 | ED2221 | 2 | | 3 | AP1111 | 3 | | 4 | AP1311 | 3 | | 5 | AS8751 | 4 | | 6 | SU9458 | 3 | +----+--------+--------+ | id | serial | id_pra | | 1 | NP3451 | 1 | | 2 | ED2221 | 2 | | 3 | AP1111 | NULL | | 4 | AP1311 | NULL | | 5 | AS8751 | 4 | | 6 | SU9458 | NULL |
Spójność dziedzinowa - CHECK CHECK zapewnia ochronę przed wstawieniem danych nie spełniających określonego warunku CREATE TABLE user( id auto_increment PRIMARY KEY, login VARCHAR(16), password VARCHAR(20), CONSTRAINT CHECK(LENGTH(password) BETWEEN 8 AND 16) ) CREATE TABLE Person( P_Id int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), CONSTRAINT chk_Person CHECK (P_Id>0 AND City='Sandnes') )
ZAPYTANIA REALIZOWANE NA WIELU TABLICACH
JOIN – w pytaniach i odpowiedziach Do czego służą operacje typu JOIN Do umożliwienia wykonywania operacji (np. SELECT) na danych przechowywanych w wielu tabelach Na jakich obiektach przeprowadza się JOIN Operacje JOIN są wykonywane na dwóch (lub więcej) tablicach (zwykle – pozostających w pewnej relacji) Jak wykonywane są "długie" operacje JOIN Każdą wielotablicową operację JOIN można rozpatrywać jako łańcuch "binarnych" (dwutablicowych) JOINów.
Dane przykładowe do operacji JOIN Rozpatrzmy dwa zbiory danych: encje STUDENT i JĘZYK create table pracownik ( id int auto_increment primary key, imie char(10), nazwisko char(30), placa int ); create table jezyk ( nazwa char(15) insert into pracownik values (1,'Jan','Nowak',3400); insert into pracownik values (2,'Ewa','Malina',2100); insert into pracownik values (3,'Iza','Trus',4000); insert into jezyk values (11,'polski'); insert into jezyk values (12,'angielski'); insert into jezyk values (13,'niemiecki'); (w tej chwili nie ma pomiędzy naszymi encjami relacji)
Iloczyn kartezjański Iloczyn kartezjański Wersja algebry relacji: Iloczynem kartezjańskim zbiorów A i B nazywamy zbiór wszystkich par (a,b), takich, że aA bB Wersja bazodanowa: iloczyn kartezjański dwóch encji A i B to zbiór wszystkich par (a,b), takich, że a jest elementem encji A, zaś b jest elementem encji B Iloczyn kartezjański zawiera KAŻDĄ możliwą parę (zbiór wszystkich par) mysql> select * from pracownik, jezyk; +----+------+----------+-------+----+-----------+ | id | imie | nazwisko | placa | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | polski | | 3 | Iza | Trus | 4000 | 11 | polski | | 1 | Jan | Nowak | 3400 | 12 | angielski | | 2 | Ewa | Malina | 2100 | 12 | angielski | | 3 | Iza | Trus | 4000 | 12 | angielski | | 1 | Jan | Nowak | 3400 | 13 | niemiecki | | 2 | Ewa | Malina | 2100 | 13 | niemiecki | | 3 | Iza | Trus | 4000 | 13 | niemiecki |
Iloczyn kartezjański a relacja Relację tworzą tylko te pary, które mają określoną właściwość (spełniają określony warunek). Innymi słowy: relacja to jeden z podzbiorów iloczynu kartezjańskiego Istnieje DUŻO możliwych relacji na dwóch encjach 1 11 1 11 2 12 2 12 3 13 3 13 Relacja A (1-do-1): jaki język obowiązuje w kraju zamieszkania pracownika Relacja B (1-do-): jakie są języki ojczyste pracowników 1 11 1 11 2 12 2 12 3 13 3 13 Relacja C (1-do-1): jakiego języka uczą się pracownicy Relacja D (-do-): jakimi językami mówią pracownicy
Relacje zaimplementowane w bazie danych Implementacja relacji wymaga dodania kolumny (zakładamy relację 1-do-) alter table pracownik add column id_jez int; Oczywiście istnieje wiele możliwych relacji 1-do- na tych encjach: 1 11 1 11 2 12 2 12 3 13 3 13 Relacja A (1-do-): jakie są języki ojczyste pracowników Relacja B (1-do-): główny język projektów naszych pracowników
Wykorzystanie operatora JOIN Operatory JOIN (binarne, czyli na dwóch encjach) dzielimy na: operatory INNER JOIN (odnoszą się tylko do elementów będących w relacji): EQUI JOIN (klasyczny INNER, wymaga równości pomiędzy kolumnami) NATURAL JOIN (wymaga równości, budowany w oparciu o nazwy kolumn) operatory OUTER JOIN (dopuszczają elementy niebędące w relacji) LEFT OUTER (wszystkie elementy z encji po lewej stronie operatora) RIGHT OUTER (wszystkie elementy z encji po prawej stronie operatora) FULL OUTER (złożenie LEFT i RIGHT) NATURAL OUTER JOIN (OUTER budowany w oparciu o nazwy kolumn) operator THETA JOIN (opiera się na warunku innym niż równość; rzadki) operator ANTI JOIN (opiera się na warunku różności; rzadki) operator CROSS JOIN (pełny iloczyn kartezjański) Operator JOIN może występować także w wersji unarnej: Operator SELF JOIN (tabela joinowana sama z sobą; raczej rzadki) Najważniejszą rolę pełnią INNER JOIN oraz OUTER JOIN (LEFT i RIGHT)
Dane do analizy Wprowadzamy dane relacji update pracownik set id_jez=11 where id=1; update pracownik set id_jez=11 where id=2; update pracownik set id_jez=12 where id=3; 1 11 2 12 3 13 Relacja (1-do-): główny język projektów naszych pracowników mysql> select * from jezyk; +----+-----------+ | id | nazwa | | 11 | polski | | 12 | angielski | | 13 | niemiecki | 3 rows in set (0.01 sec) mysql> select * from pracownik; +----+------+----------+-------+--------+ | id | imie | nazwisko | placa | id_jez | | 1 | Jan | Nowak | 3400 | 11 | | 2 | Ewa | Malina | 2100 | 11 | | 3 | Iza | Trus | 4000 | 12 | 3 rows in set (0.00 sec)
INNER JOIN INNER JOIN: wymaga klauzuli ON (opisującej kolumny używane w warunku złączenia) warunek zawsze zbudowany jest na równości (stąd nazwa: EQUI JOIN) zwraca tylko te pary, które należą do relacji (WAŻNE!) mysql> SELECT * from pracownik INNER JOIN jezyk ON (pracownik.id_jez=jezyk.id); +----+------+----------+-------+--------+----+-----------+ | id | imie | nazwisko | placa | id_jez | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | 11 | polski | | 3 | Iza | Trus | 4000 | 12 | 12 | angielski | 1 2 3 11 12 13 równość id_jez=id występuje tylko 3 przypadkach operator INNER JOIN zwraca podzbiór iloczynu kartezjańskiego element, który nie znajduje się w relacji (nie wychodzi z niego żaden łuk) NIE ZOSTANIE zawarty w wyniku INNER JOIN
OUTER JOIN OUTER JOIN: wymaga klauzuli ON (opisującej kolumny używane w warunku złączenia) warunek równość LUB brak elementu po "drugiej" stronie zwraca te pary, które należą do relacji ORAZ pary (element encji-NULL)(WAŻNE!) SELECT * from jezyk LEFT OUTER JOIN pracownik ON (jezyk.id=pracownik.id_jez); +----+-----------+------+------+----------+-------+--------+ | id | nazwa | id | imie | nazwisko | placa | id_jez | | 11 | polski | 1 | Jan | Nowak | 3400 | 11 | | 11 | polski | 2 | Ewa | Malina | 2100 | 11 | | 12 | angielski | 3 | Iza | Trus | 4000 | 12 | | 13 | niemiecki | NULL | NULL | NULL | NULL | NULL | 1 2 3 11 12 13 warunek (id=id_jez) lub (jezyk.id nie jest elementem relacji) występuje w 4 przypadkach operator OUTER JOIN zwraca podzbiór ilocz. kart. ORAZ pary zbudowane "sztucznie" z elementu NULL element, który nie znajduje się w relacji (nie wychodzi z niego żaden łuk) ZOSTANIE zawarty w wyniku OUTER JOIN (jeśli jest po "odpowiedniej stronie")
LEFT vs RIGHT OUTER JOIN LEFT OUTER JOIN select * from ksiazka LEFT OUTER JOIN autor on (ksiazka.id_aut=autor.id); KSIĄŻKA AUTOR +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | 1 2 3 11 12 13 4 1 2 3 11 12 13 4 KSIĄŻKA AUTOR 1 2 3 11 12 13 4 NULL RIGHT OUTER JOIN select * from ksiazka RIGHT OUTER JOIN autor on (ksiazka.id_aut=autor.id); Autorzy są "twórcami" książek KSIĄŻKA AUTOR +------+--------+--------+----+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | 1 2 3 11 12 13 4 NULL
LEFT, RIGHT i FULL OUTER JOIN select * from ksiazka RIGHT OUTER JOIN autor on (ksiazka.id_aut=autor.id); select * from ksiazka FULL OUTER JOIN autor on (ksiazka.id_aut=autor.id); +------+--------+--------+----+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | |NULL| NULL | NULL | 13 | Reymont | select * from ksiazka LEFT OUTER JOIN autor on (ksiazka.id_aut=autor.id); LEFT OUTER RIGHT OUTER FULL OUTER +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | 1 2 3 11 12 13 4 1 2 3 11 12 13 4 1 2 3 11 12 13 4 NULL NULL NULL NULL
OUTER JOIN vs INNER JOIN +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | 1 2 3 11 12 13 4 RIGHT OUTER FULL OUTER +------+--------+--------+----+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | |NULL| NULL | NULL | 13 | Reymont | LEFT OUTER +----+--------+--------+------+----------+ | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | LEFT OUTER RIGHT OUTER FULL OUTER 1 2 3 11 12 13 4 1 2 3 11 12 13 4 1 2 3 11 12 13 4 NULL NULL NULL NULL
NATURAL JOIN NATURAL JOIN jest przykładem JOINA, w którym: warunek ON nie jest podawany w zapytaniu, jest automatycznie generowany na podstawie NAZW kolumn jeśli używamy klauzuli USING, to specyfikujemy kolumnę (jeśli nie – brane są pod uwagę WSZYSTKIE pary o jednakowych nazwach) istnieje NATURAL JOIN (inner) oraz NATURAL [LEFT|RIGHT|FULL] OUTER select * from pracownik NATURAL JOIN dzial USING (ID_dzial); NATURAL JOIN wymaga odpowiedniego nazywania kolumn (jest to potencjalnie niebezpieczne dla nieuważnego programisty) Create table pracownik ( id int auto_increment primary key, nazwisko char(30), ID_dzial int ); Create table dzial ( ID_dzial int auto_increment primary key, nazwa char(30)
CROSS JOIN CROSS JOIN zwraca iloczyn kartezjański select * from pracownik CROSS JOIN jezyk +----+------+----------+-------+--------+----+-----------+ | id | imie | nazwisko | placa | id_jez | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | 11 | polski | | 3 | Iza | Trus | 4000 | 12 | 11 | polski | | 1 | Jan | Nowak | 3400 | 11 | 12 | angielski | | 2 | Ewa | Malina | 2100 | 11 | 12 | angielski | | 3 | Iza | Trus | 4000 | 12 | 12 | angielski | | 1 | Jan | Nowak | 3400 | 11 | 13 | niemiecki | | 2 | Ewa | Malina | 2100 | 11 | 13 | niemiecki | | 3 | Iza | Trus | 4000 | 12 | 13 | niemiecki | select * from pracownik, jezyk
GROUP BY Rozważmy następującą bazę: create table paragon ( id int auto_increment primary key, numer char(10), wartosc numeric(5,2), data_zakupu date, id_kli int ); create table klient ( nazwa char(15)
GROUP BY Dotychczas tworzyliśmy po prostu tablicę wynikową za pomocą JOIN: select nazwa, numer, wartosc from klient left outer join paragon on (klient.id=paragon.id_kli); +-----------------+-------+---------+ | nazwa | numer | wartosc | | Alfa sp. z o.o. | P001 | 110.2 | | Alfa sp. z o.o. | P002 | 20.25 | | Alfa sp. z o.o. | P003 | 311.5 | | Alfa sp. z o.o. | P008 | 45 | | Beta SA | P004 | 100.25 | | Beta SA | P005 | 70 | | Beta SA | P006 | 19.2 | | Beta SA | P007 | 30 | | Gamma Inc. | NULL | NULL | Teraz chcemy przeprowadzić operacje na grupach danych
GROUP BY GROUP BY pozwala na zastosowanie SUM do grup (a nie całości) select nazwa, wartosc from klient left outer join paragon on (klient.id=paragon.id_kli); +-----------------+---------+ | nazwa | wartosc | | Alfa sp. z o.o. | 110.2 | | Alfa sp. z o.o. | 20.25 | | Alfa sp. z o.o. | 311.5 | | Alfa sp. z o.o. | 45 | | Beta SA | 100.25 | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | select klient.id, nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) GROUP BY klient.id; +----+-----------------+--------------+ | id | nazwa | sum(wartosc) | | 1 | Alfa sp. z o.o. | 486.95 | | 2 | Beta SA | 219.45 | | 3 | Gamma Inc. | NULL | select sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli); +--------------+ | sum(wartosc) | | 706.40 |
GROUP Klauzuli GROUP BY używamy ze wszystkimi funkcjami, które mają działać na grupach danych i wyliczać dla każdej grupy reprezentującą ją wartość Wyliczoną wartość nazywamy agregatem, a funkcje – funkcjami agregującymi Funkcje agregujące to m.in. COUNT, MAX, MIN, SUM i AVG # wylicz wartość zakupów # dla każdej z firm select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # wylicz średni zakup # dla każdej z firm select nazwa, avg(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # jaki jest największy zakup # każdej z firm select nazwa, max(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # ile zakupów zrobiła # każda z firm select nazwa, count(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id;
HAVING Klauzula HAVING pozwala wyfiltrować krotki, dla których agregat spełnia określony warunek (agregat – czyli WARTOŚĆ REPREZENTUJĄCA KAŻDĄ Z GRUP) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id HAVING sum(wartosc)>300 +-----------------+--------------+ | nazwa | sum(wartosc) | | Alfa sp. z o.o. | 486.95 | +-----------------+---------+ | nazwa | wartosc | | Alfa sp. z o.o. | 110.2 | | Alfa sp. z o.o. | 20.25 | | Alfa sp. z o.o. | 311.5 | | Alfa sp. z o.o. | 45 | | Beta SA | 100.25 | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | HAVING +-----------------+--------------+ | nazwa | sum(wartosc) | | Alfa sp. z o.o. | 486.95 | | Beta SA | 219.45 | | Gamma Inc. | NULL | GROUP + SUM
HAVING vs WHERE WHERE jest filtrem dla danych PRZED agregacją, HAVING jest filtrem dla agregatów (wyników PO agregacji) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) WHERE wartosc>50 group by klient.id HAVING sum(wartosc)>200; +-----------------+---------+ | Alfa sp. z o.o. | 421.70 | HAVING +-----------------+---------+ | nazwa | wartosc | | Alfa sp. z o.o. | 421.70 | | Beta SA | 170.25 | +-----------------+---------+ | nazwa | wartosc | | Alfa sp. z o.o. | 110.2 | | Alfa sp. z o.o. | 20.25 | | Alfa sp. z o.o. | 311.5 | | Alfa sp. z o.o. | 45 | | Beta SA | 100.25 | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | GROUP+SUM +-----------------+---------+ | nazwa | wartosc | | Alfa sp. z o.o. | 110.2 | | Alfa sp. z o.o. | 311.5 | | Beta SA | 100.25 | | Beta SA | 70 | WHERE
JOIN z użyciem aliasów Użycie aliasów pozwala za skrócenie długich zapytań JOIN (ale czasem może zmniejszyć czytelność polecenia) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id HAVING sum(wartosc)>300 select nazwa, sum(wartosc) from klient as k left outer join paragon as p on (k.id=p.id_kli) group by k.id HAVING sum(wartosc)>300 select nazwa, sum(wartosc) as ile from klient as k left outer join paragon as p on (k.id=p.id_kli) group by k.id HAVING ile>300
JOIN przez kilka tabel REDUNDANCJA Ta kolumna jest niepotrzebna, dlatego należy ją usunąć!
JOIN przez kilka tabel Gdzie sprzedajemy (ile faktur w poszczególnych miastach) select miasto.nazwa, count(faktura.id) from miasto left outer join kupujacy on (miasto.id=kupujacy.id_mia) left outer join faktura on (kupujacy.id=faktura.id_kup) group by miasto.id +----------+-------------------+ | nazwa | count(faktura.id) | | Poznan | 4 | | Krakow | 3 | | Gdansk | 2 | | Warszawa | 4 | | Szczecin | 2 | | Tczew | 2 | | Sanok | 2 | | Radom | 0 |
JOIN przez kilka tabel Jakie są wartości poszczególnych faktur? select faktura.numer, sum(linia.ilosc*towar.cena) as wartosc from faktura left outer join linia on (faktura.id=linia.id_fak) left outer join towar on (linia.id_tow=towar.id) group by faktura.id +-----------+----------+ | numer | wartosc | | FV3434531 | 235.3960 | | FV3497971 | 160.7850 | | FV3543322 | 140.4060 | (...) | FV3908888 | 14.0000 | | FV1138881 | 384.0000 | | FV2333531 | 368.0000 | | FV3911188 | 42.5300 |
JOIN przez kilka tabel Ile faktur wystawili sprzedawcy? select sprzedawca.nazwisko, count(faktura.numer) as ile from sprzedawca left outer join faktura on (sprzedawca.id=faktura.id_spr) group by sprzedawca.id +----------+-----+ | nazwisko | ile | | Nowak | 4 | | Kuna | 2 | | Trus | 2 | | Pokora | 2 | | Gisz | 4 | | Wist | 1 | | Kunera | 1 | | Pokora | 1 |
O dobrym i złym projektowaniu baz danych Postaci normalne O dobrym i złym projektowaniu baz danych
Dobry diagram baz danych powinien: umożliwiać szybkie wyszukiwanie danych zapewniać łatwą modyfikowalność minimalizować szanse na wprowadzenie niespójności zapewniać brak redundancji
Powyższy diagram nie jest BŁĘDNY – jest MARNEJ JAKOŚCI Problemy: jak wyszukać pracowników z Gdańska: SELECT * from PRACOWNIK WHERE adres like '%gdańsk%' jak wyszukać pracowników z Wydziału A SELECT * from PRACOWNIK WHERE dzial like '%A%' Powyższy diagram nie jest BŁĘDNY – jest MARNEJ JAKOŚCI
Jak dobrze projektować ERD? Jak oceniać jakość diagramu ERD? POSTAĆ NORMALNA: to zbiór własności, którymi muszą się charakteryzować dane, aby mogły być uznane za znormalizowane do danej postaci. Mówimy: te dane są (lub nie) w pierwszej (drugiej, trzeciej...) postaci normalnej.
1NF Pierwsza postać normalna (1NF) wg Ch. Date: Zbiór danych jest w 1NF wtedy, gdy: nie ma powtarzających się krotek każdy atrybut jest jednowartościowy (czyli, że w danym polu można zapisać tylko jedną wartość z dopuszczalnego zbioru) nie ma wartości pustych (NULL) Wersja dla teoretyków: „zbiór danych jest w pierwszej postaci normalnej wtedy i tylko wtedy, gdy istnieje taka relacja, z którą zbiór ten jest izomorficzny
? 1NF 1NF: nie ma powtarzających się krotek: zapewniamy przez UNIQUE albo przez kolumnę ID: 1NF: jednowartościowość atrybutów i NULL: ?
UWAGA: czy DATE albo CHAR(50) jest atomem? postulat Codda do 1NF: dane powinny być "atomowe" (niepodzielne) 1 NF w wersji Codda: rekordy (krotki) są rozróżnialne atrybuty są atomowe UWAGA: czy DATE albo CHAR(50) jest atomem?
? 2NF 2NF odnosi się do wykluczenia redundancji W jaki sposób opisać to zjawisko formalnie? klucz kandydujący - jest to każdy atrybut (lub najmniejsza z możliwych grupa atrybutów), których wartość jest unikalna w danej tabeli klucz główny – arbitralnie wybrany klucz kandydujący Zależność funkcyjna pomiędzy dwoma atrybutami (kolumnami tabeli) A i B oznacza, że dla każdej wartości atrybutu A występuje zawsze jedna wartość B
Zależność funkcyjna atrybutów encji Zależność funkcyjna pomiędzy dwoma atrybutami (kolumnami tabeli) A i B oznacza, że dla każdej wartości atrybutu A występuje zawsze jedna wartość B B1 = f(A1) ale B2 nie jest f(A2)
2 NF Jakie są klucze kandydujące tabeli: Tabela jest w 2NF wtedy i tylko wtedy gdy: 1. jest w 1NF 2. żaden z atrybutów, które nie wchodzą w skład klucza kandydującego nie jest funkcjonalnie zależny od części tego klucza (inaczej: żaden z atrybutów nie jest w częściowej zależności funkcyjnej od klucza głównego) Tabela jest w 2NF wtedy i tylko wtedy gdy (mniej formalnie): 1. jest w 1NF 2. jeżeli weźmiemy dowolny klucz kandydujący i dowolny atrybut nie będący jego częścią to atrybut ten nie może być funkcją części klucza kandydującego.
2 NF Sprawdzenie: klucz kandydujący: (imię, nazwisko, język) atrybut spoza klucza: miasto klucz kandydujący vs atrybut: pełna zależność funkcyjna – ZAWSZE (dlaczego?) częściowa zależność funkcyjna – TAK MIASTO=f(imie, nazwisko) WNIOSEK: relacja nie jest w 2NF
1NF 2 NF Normalizacja do 2NF powoduje powstanie dodatkowych tablic
3NF Trzecia postać normalna jest "silniejszą wersją" 2NF Tabela jest w 3NF wtedy i tylko wtedy gdy: 1. jest w 2NF 2. nie istnieją przechodnie zależności funkcyjne Sprawdzenie częściowych zależności funkcyjnych 2NF: klucz kandydujący: Tor-Rok, atrybuty zewnętrzne: nazwisko, kraj nazwisko nie jest f(Rok), nazwisko nie jest f(Tor), kraj nie jest f(Rok), kraj nie jest f(Tor) 2NF
3NF Problem: Zależność funkcyjna przechodnia: Kraj = f(Nazwisko) UWAGA: To nie jest złamanie 2NF, bo ani kraj, ani nazwisko nie są częściami klucza kandydującego Tak wyglądać może problem wynikający z niespełnienia 3NF:
Postaci Normalne - podsumowanie UWAGA: postaci normalne można "łamać" – np. świadomie godzić się na wprowadzenie (potencjalnej) niespójności do bazy danych przykład: utworzenie tabeli przechowującej wartości zagregowane, aktualizowanej po DELETE lub INSERT przykład: dodanie kolumny kod_miasta obok kolumny miasto WNIOSKI: postaci normalne to formalny sposób oceny jakości diagramu stosujemy je po to, aby sprawdzić jakość naszych danych nie robimy tego tylko po to, aby robić – możliwe jest złamanie PN, byle ŚWIADOME
PRAWA DOSTĘPU
Prawa dostępu do obiektów w mySQL Główne zadania DBMS: Identyfikacja i autoryzacja użytkowników Definiowanie poziomów dostępu Zarządzanie prawami dostępu do obiektów Obsługa sytuacji wyjątkowych
Prawa dostępu w mySQL Prawa dotyczą obiektów bazodanowych: Połączeń, baz, tablic, triggerów Użytkowników (w mySQL - w kontekście logowania!) Polecenia związane z zarządzaniem prawami: CREATE USER RENAME USER DROP USER GRANT REVOKE SHOW GRANTS SET PASSWORD
GRANT Polecenie GRANT służy do nadawania: PRAW na OBIEKTY określonym UŻYTKOWNIKOM GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level TO user_specification [, user_specification] ... [REQUIRE {NONE | ssl_option [[AND] ssl_option] ...}] [WITH with_option ...] PRAWA (przywileje) to operacje dozwolone, np. CREATE, INSERT, SELECT, EXECUTE, FILE, RELOAD itp. OBIEKTY to tabele, kolumny, funkcje, procedury UŻYTKOWNIK jest określony kontekstem: login+hasło+adres(połączenie)
PRAWA (przywileje) W MySQL definiuje się następujące poziomy praw: global (odnosi się do całości obiektów serwera) – GRANT <prawo> on *.* database (tylko dla danej bazy danych) – GRANT <prawo> on moja.* table (tylko dla jednej tablicy w bazie) – GRANT <prawo> on moja.auto column (tylko dla określonej kolumny) – GRANT <prawo> on moja.auto(id) W zależności od poziomu prawa, są one inaczej pamiętane w systemowej bazie danych: global level – tablica mysql.user database level – tablica mysql.db table level – tablica mysql.tables_priv column level – tablica mysql.columns_priv
GRANT – SQL vs mySQL mySQL nadaje prawa w kontekście logowania (nie tylko usera) mySQL implementuje prawa globalne i bazodanowe mySQL rozszerza zakres praw w mySQL usunięcie tabeli nie usuwa praw(!); prawa-zombie mySQL pozwala na nadanie prawa INSERT do określonych kolumn, przy jednoczesnym zabraniu go na inne (użyte zostaną wartości DEFAULT)
Prawa dostępu - mySQL Najczęściej używane: Prawa do zarządzania: ALL, ALTER, DELETE, DROP, INSERT, SELECT, TRIGGER, UPDATE Prawa do zarządzania: CREATE USER, CREATE VIEW, CREATE, INDEX, EXECUTE, RELOAD, SHOW DATABASES, SHOW VIEW, SHUTDOWN, SUPER, Pozostałe: ALTER ROUTINE, CREATE ROUTINE, CREATE TEMPORARY TABLES, EVENT, FILE, LOCK TABLES, PROCESS, REPLICATION CLIENT, REPLICATION SLAVE, GRANT SELECT ON moja.samochod TO wojmos WITH GRANT OPTION Specjalne prawo: GRANT OPTION – możliwość przekazywania uprawnień
Implementacja kontekstu użytkownika Prawa użytkownika przypisuje się parze (user, host) Identyfikacja odbywa się za pomocą pary (user, password) CREATE USER user_specification [IDENTIFIED BY [PASSWORD] 'password'] UWAGA: niestosowanie klauzuli IDENTIFIED BY umożliwia logowania bez hasła IDENTIFIED BY PASSWORD umożliwia ominięcie podawania hasła otwartym tekstem mysql> create user wojmos; mysql> select user, host, password from mysql.user; +--------+-----------+-------------------------------------------+ | user | host | password | | root | localhost | *E35C24480CDB73576312748BA0DCF2E4648A7E6C | | wojmos | % | |
CREATE USER, DROP USER i SET PASSWORD CREATE USER – tworzenie użytkowników DROP USER – usuwanie użytkowników (z prawami!) SET PASSWORD – ustawianie haseł RENAME USER – zmiana nazwy GRANT USAGE CREATE USER user_specification [IDENTIFIED BY [PASSWORD] 'password'] DROP USER user [, user] ... RENAME USER old_user TO new_user SET PASSWORD [FOR user] = { 'encrypted password‘ | PASSWORD('some password') | OLD_PASSWORD('some password') } GRANT USAGE ON *.* TO ‘wojmos'@'%.wojmos.com' IDENTIFIED BY 'newpass';
Hasła podawane w CREATE USER i SET PASSWORD mysql> create user 'sample1'; mysql> create user 'sample2' identified by 'lipton'; mysql> create user 'sample3' identified by password '*90E462C37378CED12064BB3388827D2BA3A9B689'; mysql> create user 'sample3' identified by password 'lipton'; ERROR 1372 (HY000): Password hash should be a 41-digit hexadecimal number mysql> create user 'sample4'; mysql> set password for sample4 = PASSWORD('lipton'); mysql> create user 'sample5'; mysql> set password for sample5 = OLD_PASSWORD('lipton'); mysql> select user, host, password from mysql.user; +---------+-----------+-------------------------------------------+ | user | host | password | | root | localhost | *E35C24480CDB73576312748BA0DCF2E4648A7E6C | | sample2 | % | *D0CD8B382FCD172A273DE23563C530DB2E12D059 | | wojmos | % | | | sample1 | % | | | sample3 | % | *90E462C37378CED12064BB3388827D2BA3A9B689 | | sample4 | % | *D0CD8B382FCD172A273DE23563C530DB2E12D059 | | sample5 | % | 58ac86b863e0cbbf |
Przykład działania GRANT OPTION REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level FROM user [, user] ... REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ... GRANT ALL ON *.* TO wojmos with GRANT OPTION root GRANT ALL ON sample.* TO sample1 with GRANT OPTION wojmos GRANT ALL ON sample.* TO sample2 sample1 CREATE TABLE X(id int) sample2 DROP USER SAMPLE1 CREATE TABLE Y(id int) <===========? sample2
Kontekst użytkownika mySQL umożliwia dość szerokie i elastyczne zarządzanie prawami: mysql> create user koza@localhost; mysql> create user koza identified by 'lipton'; mysql> create user koza@'192.168.0.110'; mysql> create user koza@'10.10.0.'; mysqlmysql> select user, host, password from mysql.user where user like 'koza'; +------+---------------+-------------------------------------------+ | user | host | password | | koza | localhost | | | koza | % | *D0CD8B382FCD172A273DE23563C530DB2E12D059 | | koza | 192.168.0.110 | | | koza | 10.10.0. | |
Szyfrowanie tablic – bezpieczeństwo w mySQL Rozważmy typową bazę, z dostępem via Internet / PHP: USER(id int, login char(10), pass char(10), firstname char(20), lastname char(50)) Typowy (powszechne rozwiązanie) plik show.php: http://show.php?q=‘select * from product where id=7’ Typowy atak: http://show.php?q=‘select * from user’
VIEW (widok, perspektywa)
VIEW Widok (VIEW) to składowane zapytanie (stored query), które jest dostępne jako wirtualna tablica Dlaczego warto stosować widoki: Mogą pełnić rolę tablic z częścią danych (część kolumn lub część krotek) Mogą pełnić role "ukrycia" złączeń tworzonych przez JOIN Mogą pełnić rolę tablic agregujących Mogą łączyć kilka tablic na poziomie unii ("normalizacja") Mogą być wykorzystane do podnoszenia bezpieczeństwa UWAGA: Widoki przechowywane są jako zapytania, a nie jako tabele (a więc zajmują mało miejsca)
Widok select * from pracownik; +----+----------+-----------+-------+--------+ | id | imie | nazwisko | placa | id_sta | | 1 | Marek | Jackowski | 5600 | 2 | | 2 | Roman | Rendyk | 6000 | 2 | | 3 | Ewa | Tyrzyk | 8000 | 1 | | 4 | Tomasz | Pass | 6200 | 2 | | 5 | Bartosz | Nowacki | 2000 | 3 | | 6 | Wojciech | Kurtyl | 2200 | 4 | | 7 | Marek | Wiemanns | 1500 | 4 | select * from stanowisko; +----+-------------+ | id | nazwa | | 1 | dyrektor | | 2 | manager | | 3 | specjalista | | 4 | referent | create view junior_staff as select imie, nazwisko, nazwa, placa from pracownik left outer join stanowisko on (pracownik.id_sta = stanowisko.id) where not (nazwa like 'dyrektor' or nazwa like 'manager'); select * from junior_staff; +----------+----------+-------------+-------+ | Bartosz | Nowacki | specjalista | 2000 | | Wojciech | Kurtyl | referent | 2200 | | Marek | Wiemanns | referent | 1500 |
VIEW create view kadra as select imie, nazwisko, nazwa from sprzedawca left outer join miasto on (sprzedawca.id_mia=miasto.id); select * from kadra; +--------+----------+----------+ | imie | nazwisko | nazwa | | Jan | Nowak | Poznan | | Piotr | Kuna | Poznan | | Ewa | Trus | Krakow | | Iza | Pokora | Sanok | | Kasia | Gisz | Sanok | | Janusz | Wist | Warszawa | | Stefan | Kunera | Krakow | | Marek | Pokora | Poznan | select * from kadra_agr; +----------+-----+------------+ | nazwa | ile | avg(placa) | | Poznan | 3 | 1733.3333 | | Krakow | 2 | 1800.0000 | | Warszawa | 1 | 1900.0000 | | Sanok | 2 | 2100.0000 | create view kadra_agr as select nazwa, count(sprzedawca.id) as ile, avg(placa) from sprzedawca left outer join miasto on (sprzedawca.id_mia=miasto.id) group by miasto.id;
Widok a bezpieczeństwo Nadawanie praw dostępu create view junior_staff as select imie, nazwisko, nazwa, placa from pracownik left outer join stanowisko on (pracownik.id_sta=stanowisko.id) where not (nazwa like 'dyrektor' or nazwa like 'manager'); create user bazak; grant all on rbd6.junior_staff to bazak; select * from pracownik; ERROR 1142 (42000): SELECT command denied to user 'bazak'@'localhost' for table 'pracownik' select * from junior_staff; +----------+----------+-------------+-------+ | imie | nazwisko | nazwa | placa | | Bartosz | Nowacki | specjalista | 2000 | | Wojciech | Kurtyl | referent | 2200 | | Marek | Wiemanns | referent | 1500 |
Widok a aktualność danych Ponieważ widok jest tabelą wirtualną, to zmiany wprowadzone w tabelach oryginalnych, przekładają się na dane w widoku select * from junior_staff; +----------+----------+-------------+-------+ | imie | nazwisko | nazwa | placa | | Bartosz | Nowacki | specjalista | 2000 | | Wojciech | Kurtyl | referent | 2200 | | Marek | Wiemanns | referent | 1500 | update pracownik set placa=2500 where nazwisko like 'Nowacki'; | Bartosz | Nowacki | specjalista | 2500 |
Widok a spójność tabel Widok a modyfikacja struktury tabel – dodanie kolumny drop view if exists banal; create view banal as select * from pracownik; select * from banal; alter table pracownik add column plec char(1) default 'm'; update pracownik set plec='k' where id=3; select * from pracownik; +----+----------+-----------+-------+--------+------+ | id | imie | nazwisko | placa | id_sta | plec | | 1 | Marek | Jackowski | 5600 | 2 | m | | 2 | Roman | Rendyk | 6000 | 2 | m | | 3 | Ewa | Tyrzyk | 8000 | 1 | k | mysql> select * from banal; +----+----------+-----------+-------+--------+ | id | imie | nazwisko | placa | id_sta | | 1 | Marek | Jackowski | 5600 | 2 | | 2 | Roman | Rendyk | 6000 | 2 | | 3 | Ewa | Tyrzyk | 8000 | 1 |
Widok a spójność tabel Widok a modyfikacja struktury tabel – usunięcie kolumny drop view if exists banal; create view banal as select * from pracownik; select * from banal; alter table pracownik drop column imie; select * from pracownik; +----+-----------+-------+--------+------+ | id | nazwisko | placa | id_sta | plec | | 1 | Jackowski | 5600 | 2 | m | | 2 | Rendyk | 6000 | 2 | m | | 3 | Tyrzyk | 8000 | 1 | k | | 4 | Pass | 6200 | 2 | m | | 5 | Nowacki | 2500 | 3 | m | | 6 | Kurtyl | 2200 | 4 | m | | 7 | Wiemanns | 1500 | 4 | m | mysql> select * from banal; ERROR 1356 (HY000): View 'rbd6.banal' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
Widoki z możliwością aktualizacji Wymogi na możliwość aktualizacji danych bazowych przez widok Nie może zawierać funkcji agregujących Nie może zawierać DISTINCT Nie może używać operatora GROUP BY i HAVING Nie może zawierać unii Nie może być zbudowany w oparciu o widok, który nie umożliwia UPDATE Nie może zawierać wielu odniesień do tej samej kolumny Nie może zawierać niektórych rodzajów JOIN
Widok z możliwością aktualizacji tabel bazowych Aktualizacja danych (UPDATE) update V1 set nazwa='Puck' where nazwa like 'Tczew'; select * from V1; +-----+----------+--------+--------+------+----------+ | ids | nazwisko | indeks | id_mia | idm | nazwa | | 1 | Kowal | s3472 | 1 | 1 | Warszawa | | 2 | Nowak | s1231 | 2 | 2 | Puck | | 3 | Kopek | s2945 | 2 | 2 | Puck | select * from miasto; +-----+----------+ | idm | nazwa | | 1 | Warszawa | | 2 | Puck |
Widoki z możliwością wstawienia Wymogi na możliwość wstawiania danych bazowych przez widok Widok musi być klasy "updateable" Nie może być kolumn o takiej samej nazwie w tablicach bazowych Widok musi zawierać wszystkie kolumny z tablic bazowych, które nie mają ustawionej wartości domyślnej (DEFAULT) Wszystkie kolumny muszą być referencjami prostymi z tablic bazowych (tzn. nie mogą być wyliczane na postawie innych kolumn)
Widoki z możliwością wstawienia create table miasto ( idm int auto_increment primary key, nazwa char(25) ); create table student ( ids int auto_increment primary key, imie char(20), nazwisko char(25), id_mia int, FOREIGN KEY (id_mia) REFERENCES miasto(idm) ON UPDATE CASCADE create view V2 as select nazwa, imie, nazwisko from student left outer join miasto on (student.id_mia=miasto.idm); insert into V2(nazwa, imie, nazwisko, id_mia) values ('Ewa','Peszek',1); ERROR 1471 (HY000): The target table V2 of the INSERT is not insertable-into
Widoki z możliwością wstawienia create table miasto (idm int auto_increment primary key, nazwa char(25)); create table student ( ids int auto_increment primary key, imie char(20), nazwisko char(25), id_mia int, FOREIGN KEY (id_mia) REFERENCES miasto(idm) ON UPDATE CASCADE ); create view V3 as select imie, nazwisko from student; insert into V3(imie, nazwisko) values ('Ewa','Peszek'); insert into V3(imie, nazwisko) values ('Ewa','Peszek'); mysql> select * from V3; +------+----------+ | imie | nazwisko | | Jan | Kowal | | Iza | Nowak | | Ewa | Peszek | mysql> select * from student; +-----+------+----------+--------+ | ids | imie | nazwisko | id_mia | | 1 | Jan | Kowal | 1 | | 2 | Iza | Nowak | 2 | | 3 | Ewa | Peszek | NULL |
(zagnieżdżone zapytania SQL) NESTED SQL (zagnieżdżone zapytania SQL)
Zagnieżdżone zapytanie SQL Zagnieżdżone zapytanie SQL – częścią zapytania (najczęściej warunek WHERE coś IN (…) jest osobne zapytanie SQL SELECT * FROM pracownik WHERE id_dzi = (SELECT id FROM dzial); UWAGA: nawiasy otaczające podzapytanie są niezbędne Zagnieżdżonych SQL można używać z SELECT, INSERT, UPDATE i DELETE W przypadku zapytań modyfikujących (INSERT, UPDATE, DELETE) nie jest możliwe wykonywanie SELECT na tej samej tablicy w podzapytaniu Nested SQL czy JOIN?
UNION (unia)
UNION Co to jest unia? Jakie są wymogi na stosowanie unii? UNION jest operatorem pozwalającym na sumowanie tabel wynikowych dwóch zapytań SELECT Jakie są wymogi na stosowanie unii? Łączone tabele muszą być "kompatybilne", czyli mieć tą samą liczbę kolumn, a kolumny powinny być "podobne" względem typu Po co stosuje się unie? Wygodne narzędzie pracy na nieznormalizowanych bazach danych (lub z wykorzystaniem widoków) Jakie są rodzaje unii? UNION – zwykła unia (automatyczne odrzucenie duplikatów) UNION ALL – eliminuje powtarzające się krotki (jak DISTINCT)
+ = UNION Unie pozwalają na łączenie zbiorów danych mysql> select * from faktury_historyczne union select * from faktury_biezace; +----+-------------+----------+----------+--------+ | id | data_zakupu | wartosc | VAT | id_kli | | 1 | 2009-04-05 | 6000.00 | 7320.00 | 1 | | 2 | 2010-05-10 | 3000.00 | 3660.00 | 1 | | 3 | 2008-11-12 | 15000.00 | 18300.00 | 2 | | 4 | 2009-10-10 | 2000.00 | 2440.00 | 3 | | 1 | 2011-05-09 | 7000.00 | 8610.00 | 1 | | 2 | 2011-06-01 | 1000.00 | 1230.00 | 4 | 6 rows in set (0.00 sec)
+ = UNION i podzapytania Wykorzystanie unii w podzapytaniach UWAGA: konieczne jest zastosowanie klauzuli AS! select sum(wartosc) from (select * from faktury_historyczne union select * from faktury_biezace); ERROR 1248 (42000): Every derived table must have its own alias select sum(wartosc) from (select * from faktury_historyczne union select * from faktury_biezace) as sb; +--------------+ | sum(wartosc) | | 34000.00 | 1 row in set (0.00 sec)
Wybrane funkcje wbudowane
Najważniejsze funkcje operujące na łańcuchach ASCII() Konwersja znaku na kod (odwrotnie: ORD()) mysql> SELECT ASCII('2'); -> 50 mysql> SELECT ASCII(2); mysql> SELECT ASCII('dx'); -> 100 BIN() Konwersja liczby zapisanej jako tekst na system binarny mysql> SELECT BIN(12); -> '1100' BIN_LENGTH() zwraca długość łancucha (w bitach!) mysql> SELECT BIT_LENGTH('text'); -> 32
Najważniejsze funkcje operujące na łańcuchach CHAR() – konwersja argumentów (int) na sklejony łańcuch mysql> SELECT CHAR(77,121,83,81,'76'); -> 'MySQL' mysql> SELECT CHAR(77,77.3,'77.3'); -> 'MMM' CHAR(int USING str) – konwersja z użyciem zestawu znaków mysql> SELECT CHARSET(CHAR(0x65)), CHARSET(CHAR(0x65 USING utf8)); +---------------------+--------------------------------+ | CHARSET(CHAR(0x65)) | CHARSET(CHAR(0x65 USING utf8)) | | latin1 | utf8 | CHAR_LENGTH() – długość łańcucha mysql> SELECT CHAR_LENGTH('ABC'); -> 3
Najważniejsze funkcje operujące na łańcuchach CONCAT() – skleja łańcuchy mysql> SELECT CONCAT('My', 'S', 'QL'); -> 'MySQL' mysql> SELECT CONCAT('My', NULL, 'QL'); -> NULL mysql> SELECT CONCAT(14.3); -> '14.3' CONCAT() – wersja skrócona: mysql> SELECT 'My' 'S' 'QL'; -> 'MySQL' CONCAT_WS() – wersja z separatorem: mysql> SELECT CONCAT_WS(',','First name','Second name','Last Name'); -> 'First name,Second name,Last Name' mysql> SELECT CONCAT_WS(',','First name',NULL,'Last Name'); -> 'First name,Last Name'
Najważniejsze funkcje operujące na łańcuchach ELT(int, str, str, …) – podaje n-ty element z listy mysql> SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo'); -> 'ej' mysql> SELECT ELT(4, 'ej', 'Heja', 'hej', 'foo'); -> 'foo' FIND(str, str1, str2…) – podaje pozycję str w liście str1, str2… mysql> SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo'); -> 2 mysql> SELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo'); -> 0 FORMAT(X, D) – formatuje x do D miejsc dziesiętnych (z sep.) mysql> SELECT FORMAT(12332.123456, 4); -> '12,332.1235' mysql> SELECT FORMAT(12332.1,4); -> '12,332.1000' mysql> SELECT FORMAT(12332.2,0); -> '12,332'
Najważniejsze funkcje operujące na łańcuchach HEX(int) – konwersja na system szesnastkowy mysql> SELECT HEX(255), CONV(HEX(255),16,10); -> 'FF', 255 HEX(str) – konwersja STRINGU na reprezentację szesnastkową ysql> SELECT 0x616263, HEX('abc'), UNHEX(HEX('abc')); -> 'abc', 616263, 'abc' INSERT() – wstawianie do łańcucha mysql> SELECT INSERT('Quadratic', 3, 4, 'What'); -> 'QuWhattic' mysql> SELECT INSERT('Quadratic', -1, 4, 'What'); -> 'Quadratic' mysql> SELECT INSERT('Quadratic', 3, 100, 'What'); -> 'QuWhat' INSTR() – wyszukiwanie w łańcuchu mysql> SELECT INSTR('foobarbar', 'bar'); -> 4
Najważniejsze funkcje operujące na łańcuchach LEFT() – wycinanie lewej części łańcucha mysql> SELECT LEFT('foobarbar', 5); -> 'fooba' LENGTH() – podaje długość łańcucha w bajtach (multibajty!) mysql> SELECT LENGTH('text'); -> 4 mysql> SELECT LENGTH('ąść'); -> 6 LOAD_FILE() – zwraca plik dyskowy mysql> UPDATE t SET blob_col=LOAD_FILE('/tmp/picture') WHERE id=1;
Najważniejsze funkcje operujące na łańcuchach LOWER() – zmniejszenie znaków (łańcuch nie może być binarny!) mysql> SET @str = BINARY 'New York'; mysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING latin1)); +-------------+-----------------------------------+ | LOWER(@str) | LOWER(CONVERT(@str USING latin1)) | | New York | new york | LTRIM() – obcinanie znaków spacji po lewej stronie mysql> SELECT LTRIM(' barbar'); -> 'barbar' ORD() – podaje kod znaku (znaków) mysql> SELECT ORD('2'); -> 50 REPEAT() – powtarza sekwencję mysql> SELECT REPEAT('MySQL', 3); -> 'MySQLMySQLMySQL'
Najważniejsze funkcje operujące na łańcuchach REVERSE() – odwraca łańcuch mysql> SELECT REVERSE('abc'); -> 'cba' RTRIM() – usuwa nadmiarowe spacje z prawej strony mysql> SELECT RTRIM('barbar '); -> 'barbar' SPACE() – tworzy n spacji mysql> SELECT SPACE(6); -> ' ' TRIM() – usuwa wybrane znaki mysql> SELECT TRIM(' bar '); -> 'bar' mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx'); -> 'barxxx' mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx'); mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz'); -> 'barx'
Najważniejsze funkcje operujące na łańcuchach SUBSTRING() – wyszukiwanie w łańcuchu mysql> SELECT SUBSTRING('Quadratically',5); -> 'ratically' mysql> SELECT SUBSTRING('foobarbar' FROM 4); -> 'barbar' mysql> SELECT SUBSTRING('Quadratically',5,6); -> 'ratica' mysql> SELECT SUBSTRING('Sakila', -3); -> 'ila' mysql> SELECT SUBSTRING('Sakila', -5, 3); -> 'aki' mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2); -> 'ki' UPPER() – odwrotnie do LOWER() mysql> SELECT UPPER('Hej'); -> 'HEJ'
Funkcje czasu i daty w SQL/MySQL
Kalendarz juliański, kalendarz gregoriański Kalendarz juliański – opracowany na życzenie Juliusza Cezara, zastąpił kalendarz księżycowy, wprowadzony 45 pne Kalendarz solarny Wprowadził poprawkę niwelującą błędy (jeden miesiąc w 46 roku wydłużono o 90 dni) 365 dni + 1 dzień przestępny co 4 lata (początkowo co 3 lata) Opóźnienie 1 dzień na 128 lat Kalendarz gregoriański – wprowadzony bullą Inter gravissimas przez papieża Grzegorza XIII. Wprowadził poprawkę niwelującą błędy juliańskie (10 brakujących dni) Opóźnienie 1 dzień na 3322 lata Lata przestępne: co 4 lata z wyjątkiem lat podzielnych przez 100, ale niepodzielnych przez 400
Kalendarz juliański, kalendarz gregoriański
Funkcje daty i czasu ADDDATE(date,INTERVAL expr unit) – dodaje odstęp do daty mysql> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY); -> '2008-02-02'
Funkcje daty i czasu ADDTIME(date,INTERVAL expr unit) – dodaje odstęp do daty mysql> SELECT ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002'); -> '2008-01-02 01:01:01.000001' mysql> SELECT ADDTIME('01:00:00.999999', '02:00:00.999998'); -> '03:00:01.999997'
Funkcje daty i czasu CONVERT_TZ(dt,from_tz,to_tz) – konwersja na strefę czasową mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET'); -> '2004-01-01 13:00:00' mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00'); -> '2004-01-01 22:00:00' CURDATE() – aktualna data mysql> SELECT CURDATE(); -> '2008-06-13' mysql> SELECT CURDATE() + 0; -> 20080613 CURTIME() – aktualny czas mysql> SELECT CURTIME(); -> '23:50:26' mysql> SELECT CURTIME() + 0; -> 235026.000000
Funkcje daty i czasu CURTIMESTAMP() – aktualny czas (zamiennik dla NOW()) mysql> SELECT NOW(); -> '2007-12-15 23:50:26' mysql> SELECT NOW() + 0; -> 20071215235026.000000 DATE() – podaje jedynie część "data" mysql> SELECT DATE('2003-12-31 01:02:03'); -> '2003-12-31' DATEDIFF() – podaje różnicę w dacie (tylko część "data") mysql> SELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30'); -> 1 mysql> SELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31'); -> -31
Funkcje daty i czasu DATE_FORMAT() mysql> SELECT 22:23:00', '%W %M %Y'); -> 'Sunday October 2009' mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', -> '%H:%i:%s'); -> '22:23:00' mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00', -> '%D %y %a %d %m %b %j'); -> '4th 00 Thu 04 10 Oct 277' mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00', -> '%H %k %I %r %T %S %w'); -> '22 22 10 10:23:00 PM 22:23:00 00 6' mysql> SELECT DATE_FORMAT('1999-01-01', -> '%X %V'); -> '1998 52' mysql> SELECT DATE_FORMAT('2006-06-00', -> '%d'); -> '00'
Funkcje daty i czasu DAYNAME() – podaje nazwę dnia mysql> SELECT DAYNAME('2007-02-03'); -> 'Saturday' DAYNAME() – podaje numer dnia w standardzie ODBC mysql> SELECT DAYOFWEEK('2007-02-03'); -> 7 EXTRACT() – podaje odpowiednią część daty mysql> SELECT EXTRACT(YEAR FROM '2009-07-02'); -> 2009 mysql> SELECT EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03'); -> 200907 mysql> SELECT EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03'); -> 20102 mysql> SELECT EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123'); -> 123
Funkcje daty i czasu FROMDAYS() – podaje datę na podstawie numeru dnia mysql> SELECT FROM_DAYS(730669); -> '2007-07-03' FROM_UNIXTIME() – podaje datę we timestamp unixa mysql> SELECT FROM_UNIXTIME(1196440219); -> '2007-11-30 10:30:19' mysql> SELECT FROM_UNIXTIME(1196440219) + 0; -> 20071130103019.000000 mysql> SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(), -> '%Y %D %M %h:%i:%s %x'); -> '2007 30th November 10:30:59 2007' HOUR() – podaje godzinę mysql> SELECT HOUR('10:05:03'); -> 10
Funkcje daty i czasu LASTDAY () – podaje ostatni dzień wskazanego miesiąca mysql> SELECT LAST_DAY('2003-02-05'); -> '2003-02-28' mysql> SELECT LAST_DAY('2004-02-05'); -> '2004-02-29' mysql> SELECT LAST_DAY('2004-01-01 01:01:01'); -> '2004-01-31' mysql> SELECT LAST_DAY('2003-03-32'); -> NULL MAKEDATE () – podaje utworzoną datę mysql> SELECT MAKEDATE(2011,31), MAKEDATE(2011,32); -> '2011-01-31', '2011-02-01' mysql> SELECT MAKEDATE(2011,365), MAKEDATE(2014,365); -> '2011-12-31', '2014-12-31' mysql> SELECT MAKEDATE(2011,0); -> NULL
Funkcje daty i czasu MONTHNAME() – podaje nazwę miesiąca mysql> SELECT MONTHNAME('2008-02-03'); -> 'February' NOW() – aktualny timestamp mysql> SELECT NOW(); -> '2007-12-15 23:50:26' mysql> SELECT NOW() + 0; -> 20071215235026.000000 QUARTER() – podaje nazwę kwartału mysql> SELECT QUARTER('2008-04-01'); -> 2 SEC_TO_TIME() – zmienia sekundy na godzinę mysql> SELECT SEC_TO_TIME(2378); -> '00:39:38'
Funkcje daty i czasu STR_TO_DATE() – zamienia łańcuch na datę mysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y'); -> '2013-05-01' mysql> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y'); mysql> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s'); -> '09:30:17' mysql> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s'); -> NULL mysql> SELECT STR_TO_DATE('abc','abc'); -> '0000-00-00' mysql> SELECT STR_TO_DATE('9','%m'); -> '0000-09-00' mysql> SELECT STR_TO_DATE('9','%s'); -> '00:00:09'
Wbudowane funkcje kontroli sterowania (uwaga: nie mylić z instrukcjami kontroli sterowania) FUNKCJE STEROWANIA – używamy w SQL INSTRUKCJE STEROWANIA – używamy w procedurach
Funkcje sterowania IF(expr1, expr2, expr3) – jak IF w Excelu mysql> SELECT IF(1>2,2,3); -> 3 mysql> SELECT IF(1<2,'yes','no'); -> 'yes' mysql> SELECT IF(STRCMP('test','test1'),'no','yes'); -> 'no' mysql> SELECT IF(0.1,1,0); -> 0 mysql> SELECT IF(0.1<>0,1,0); -> 1 IFNULL(expr1, expr2) – sprawdzenie, czy NULL mysql> SELECT IFNULL(1,0); -> 1 mysql> SELECT IFNULL(NULL,10); -> 10 mysql> SELECT IFNULL(1/0,10); mysql> SELECT IFNULL(1/0,'yes'); -> 'yes'
Funkcje sterowania CASE – wersja 1: zwraca result, jeżeli value=compare_value CASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN result ...] [ELSE result] END CASE – wersja 2: zwraca result, dla pierwszego spełnionego warunku CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END mysql> SELECT CASE 1 -> WHEN 1 THEN 'one' -> WHEN 2 THEN 'two' -> ELSE 'more' END; -> 'one' mysql> SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END; -> 'true' mysql> SELECT CASE BINARY 'B' -> WHEN 'a' THEN 1 WHEN 'b' THEN 2 END; -> NULL
Problemy związane z językami lokalnymi
Character set Character set – zestaw znaków wraz z kodowaniem 1 A 6 B 2 Ą 3 4 2 3 5 Zestaw znaków zawiera wszystkie możliwe symbole wraz z ich kodami. Dwom różnym symbolom (np. "a" i "A") odpowiadają zawsze dwa różne kody. Należy rozróżnić symbol od kodu, nawet jeśli "wyglądają" podobnie. Innymi słowy symbolowi "2" może odpowiadać kod 2 (albo inny).
Zestawy znaków i porównania Sprawdzenie dostępnych zestawów znaków: mysql> SHOW CHARACTER SET; +----------+-----------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | | big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 | | dec8 | DEC West European | dec8_swedish_ci | 1 | | cp850 | DOS West European | cp850_general_ci | 1 | | hp8 | HP West European | hp8_english_ci | 1 | | koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 | | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 | | swe7 | 7bit Swedish | swe7_swedish_ci | 1 | | ascii | US ASCII | ascii_general_ci | 1 | ...
Collation - porównanie Collation to metoda porównywania symboli. a 1 A 6 B 2 3 ż 4 z ź 5 Dla każdego zestawu znaków zawsze istnieje najprostsze porównanie: symbole są różne, jeśli różne są ich kody. Jest to tzw. Porównanie binarne. Przykład innego porównania (collation): a 1 A 6 B 2 3 ż 4 z ź 5
Collation Sprawdzenie dostępnych porównań: mysql> SHOW COLLATION LIKE 'latin1%'; +-------------------+---------+----+---------+----------+---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | | latin1_german1_ci | latin1 | 5 | | | 0 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 0 | | latin1_danish_ci | latin1 | 15 | | | 0 | | latin1_german2_ci | latin1 | 31 | | Yes | 2 | mysql> SHOW COLLATION WHERE `Default` = 'Yes'; +---------------------+----------+----+---------+----------+---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | | big5_chinese_ci | big5 | 1 | Yes | Yes | 1 | | dec8_swedish_ci | dec8 | 3 | Yes | Yes | 1 | | cp850_general_ci | cp850 | 4 | Yes | Yes | 1 | | hp8_english_ci | hp8 | 6 | Yes | Yes | 1 | | koi8r_general_ci | koi8r | 7 | Yes | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 |
Ustawianie lokalizacji domyślnej Dla całego serwera: mysqld --character-set-server=latin1 ./configure --with-charset=latin1 Dla określonej bazy danych: CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] ALTER DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] Dla tabeli: CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]
Ustawianie lokalizacji domyślnej Dla kolumny w tabeli: CREATE TABLE t1 ( col1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_german1_ci ); ALTER TABLE t1 MODIFY col1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_swedish_ci; Uwaga: zmiana zestawu znaków dla tabeli/kolumny/bazy, w której istnieją dane może doprowadzić do utraty danych
Tworzenie własnych funkcji i procedur
Tworzenie własnych funkcji i procedur Funkcje są definiowanymi przez użytkownika rozszerzeniami SQL. MySQL pozwala na 3 mechanizmy: Funkcje wkompilowywane w kod serwera Funkcje w postaci kompilowanych bibliotek Funkcje i procedury składowane (stored functions/procedures) (Zwykły użytkownik zasadniczo używa jedynie 3 drogi) Stored function (funkcja składowana) jest wywoływana tak, jak zwykła funkcja SQL. Stored procedure (procedura składowana) jest wywoływana przez call select concat('Ala', ' ma kota'); select count(*) from user; select moja_funkcja(); call moja_procedura();
Własne funkcje CREATE PROCEDURE/FUNCTION DROP PROCEDURE/FUNCTION SHOW PROCEDURE/FUNCTION STATUS SHOW CREATE PROCEDURE/FUNCTION Procedury i funkcje są obiektami konkretnej bazy (od 5.0.1+)! Procedury i funkcje są obiektami serwera (do 5.0.0)! mysql> show function status; +-----------+---------+----------+----------------+---------------------+---------------------+---------------+---------+ | Db | Name | Type | Definer | Modified | Created | Security_type | Comment | | poligon | nazwa | FUNCTION | root@localhost | 2009-12-10 21:36:12 | 2009-12-10 21:36:12 | DEFINER | | | populacja | exp2lvl | FUNCTION | root@localhost | 2009-08-21 16:35:32 | 2009-08-21 16:35:32 | DEFINER | | 2 rows in set (0.00 sec)
Funkcje vs procedury Funkcje i procedury składowane mają podobną budowę i znaczenie Funkcje wymagają określenia RETURNS Funkcje składowane i UDF dzielą ze sobą przestrzeń nazw Parametry funkcji są zawsze IN (nie mogą zmienić wartości) Funkcje są wywoływane jak normalne funkcje SQL CREATE [DEFINER] FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [special ...] routine_body func_parameter: name type special: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string' routine_body: SQL | BEGIN...END
Funkcje vs procedury Funkcje i procedury składowane mają podobną budowę i znaczenie Procedury nie określają RETURNS – nie zwracają wartości Procedury przekazują wartości tylko przez zmienne Parametry procedur mogą być IN, OUT lub INOUT Procedury wywoływane są tylko poprzez call CREATE [DEFINER] PROCEDURE sp_name ([proc_parameter[,...]]) [special...] routine_body proc_parameter: [ IN | OUT | INOUT ] name type special: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string' routine_body: SQL | BEGIN...END
Porównanie CREATE dla funkcji i procedur [DEFINER = { user | CURRENT_USER }] PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine_body FUNCTION sp_name ([func_parameter[,...]]) RETURNS type proc_parameter: [ IN | OUT | INOUT ] param_name type func_parameter: param_name type type: Any valid MySQL data type characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string'
DELIMITER i jego znaczenie Procedury i funkcje składają się zwykle z wielu linii kodu. Oznacza to problem z interpretacją znaku ; po stronie klienta. PRZYPOMINAMY: znak terminalny „;” powoduje natychmiastowe wysłanie poleceń do serwera (w celu interpretacji). Druga jego rola to oddzielanie kolejnych poleceń. CREATE FUNCTION nazwa () RETURNS VARCHAR(20) BEGIN RETURN 'Hello world'; END; w tym miejscu kod zostanie wysłany do serwera CREATE FUNCTION nazwa () RETURNS VARCHAR(20) BEGIN RETURN 'Hello world'; powyższy fragment NIE JEST jednak poprawny!
DELIMITER – zmiana znaku terminalnego WNIOSEK: musimy chwilowo zmienić znaczenie znaku ; (aby przestał wysyłać kod do serwera). DELIMITER ;; nowy symbol terminalny CREATE FUNCTION nazwa () RETURNS VARCHAR(20) BEGIN RETURN ‘Hello world'; END; tworzymy funkcję koniec polecenia ;; wysyłamy do serwera DELIMITER ; stary symbol terminalny (sprzątamy po sobie!)
Prosta funkcja składowana Stworzenie funkcji mysql> DROP FUNCTION IF EXISTS Hello; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show warnings; +-------+------+-------------------------------+ | Level | Code | Message | | Note | 1305 | FUNCTION Hello does not exist | DELIMITER ;; CREATE FUNCTION Hello() RETURNS VARCHAR(20) BEGIN RETURN 'Hello world'; END; ;; DELIMITER ;
Prosta funkcja składowana Stworzenie i wywołanie funkcji DROP FUNCTION IF EXISTS Hello; DELIMITER ;; CREATE FUNCTION Hello() RETURNS VARCHAR(20) BEGIN RETURN 'Hello world'; END; ;; DELIMITER ; mysql> select hello(); +-------------+ | hello() | | Hello world | 1 row in set (0.00 sec)
Prosta procedura składowana Stworzenie procedury mysql> DROP PROCEDURE IF EXISTS Hello; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show warnings; +-------+------+--------------------------------+ | Level | Code | Message | | Note | 1305 | PROCEDURE Hello does not exist | DELIMITER ;; CREATE PROCEDURE Hello() BEGIN SELECT('Hello world'); END; ;; DELIMITER ;
Prosta funkcja składowana Stworzenie i wywołanie procedury DROP PROCEDURE IF EXISTS Hello; DELIMITER ;; CREATE PROCEDURE Hello() BEGIN SELECT('Hello world'); END; ;; DELIMITER ; mysql> call hello(); +-------------+ | Hello world | 1 row in set (0.00 sec)
Parametry przekazywane do obiektów składowanych Funkcje – parametry zawsze są traktowane jako IN Procedury – parametry mogą mieć typ IN, OUT lub INOUT IN – parametr wejściowy, modyfikacja nie jest widoczna na zewnątrz (inicjalizuje go obiekt wywołujący funkcję) OUT – parametr wyjściowy, pełni rolę wartości zwracanej przez zmienną, ma inicjalnie ustawianą wartość na NULL (inicjalizuje go funkcja) INOUT - parametr wejściowo-wyjściowy, pełni rolę wartości zwracanej przez zmienną, ma inicjalnie ustawianą wartość przez obiekt wywołujący funkcję Dane do przykładu mysql> select * from pracownik; +--------+-----------+-----------+-------------+----------+ | Jan | Kowalski | polski | 73020103456 | Gdansk | | Jan | Kowalski | niemiecki | 73020103456 | Gdansk | | Piotr | Nowak | polski | 43121102934 | Szczecin | | Stefan | Kozlowski | polski | 98101045777 | Warszawa | | Piotr | Nowak | angielski | 43121102934 | Szczecin | | Jan | Kurski | polski | 71101099348 | Gdansk |
Parametry IN Procedura z parametrem typu IN Wywołanie CREATE PROCEDURE Sample(IN parametr char(30)) BEGIN SELECT * FROM pracownik WHERE i LIKE parametr; END; mysql> call Sample('Jan'); +------+----------+-----------+-------------+--------+ | i | n | j | p | miasto | | Jan | Kowalski | polski | 73020103456 | Gdansk | | Jan | Kowalski | niemiecki | 73020103456 | Gdansk | | Jan | Kurski | polski | 71101099348 | Gdansk | 3 rows in set (0.00 sec)
Parametry OUT Procedura z parametrem typu OUT Wywołanie CREATE PROCEDURE Sample(OUT parametr char(30)) BEGIN SELECT count(*) FROM pracownik into parametr; END; call sample(@zmienna); select @zmienna; Query OK, 0 rows affected (0.00 sec) +----------+ | @zmienna | | 6 | 1 row in set (0.00 sec)
Parametry OUT Parametr typu OUT ma inicjalną wartość NULL Wywołanie CREATE PROCEDURE Sample(OUT parametr char(30)) BEGIN SELECT parametr; SELECT count(*) FROM pracownik into parametr; END; mysql> call sample(@zmienna); +----------+ | parametr | | NULL | mysql> call sample('Jan'); ERROR 1414 (42000): OUT or INOUT argument 1 for routine wojmos.sample is not a variable or NEW pseudo-variable in BEFORE trigger
Parametry OUT Parametr typu OUT ma ZAWSZE inicjalną wartość NULL Wywołanie CREATE PROCEDURE Sample(OUT parametr char(30)) BEGIN SELECT parametr; SELECT count(*) FROM pracownik into parametr; END; mysql> select @a:=3; call sample(@a); +-------+ | @a:=3 | | 3 | +----------+ | parametr | | NULL |
Parametry INOUT Procedura z parametrem typu INOUT Wywołanie (parametr inicjowany przez obiekt wołający!) CREATE PROCEDURE Sample(INOUT parametr char(30)) BEGIN SELECT parametr; SELECT count(*) FROM pracownik into parametr; END; mysql> select @a:=3; call sample(@a); +-------+ | @a:=3 | | 3 | +----------+ | parametr | | 3 |
Parametry INOUT Procedura z parametrem typu INOUT Wywołanie (parametr inicjowany przez obiekt wołający!) CREATE PROCEDURE Sample(INOUT parametr char(30)) BEGIN SELECT parametr; SELECT count(*) FROM pracownik into parametr; END; mysql> call sample(@a); select @a; +----------+ | parametr | | 3 | +------+ | @a | | 6 |
Własne funkcje SHOW PROCEDURE/FUNCTION STATUS mysql> show function status; +-----------+---------+----------+----------------+---------------------+---------------------+---------------+---------+ | Db | Name | Type | Definer | Modified | Created | Security_type | Comment | | poligon | nazwa | FUNCTION | root@localhost | 2009-12-10 21:36:12 | 2009-12-10 21:36:12 | DEFINER | | | populacja | exp2lvl | FUNCTION | root@localhost | 2009-08-21 16:35:32 | 2009-08-21 16:35:32 | DEFINER | | 2 rows in set (0.00 sec) mysql> show function status; +-----------+---------+----------+----------------+ | Db | Name | Type | Definer | | poligon | nazwa | FUNCTION | root@localhost | | populacja | exp2lvl | FUNCTION | root@localhost |
Budowa obiektów składowanych - zmienne Zmienne w programach składowanych zmienne sesyjne zmienne lokalne (dla bloków BEGIN-END) Zmienne lokalne: deklarowane za pomocą DECLARE muszą być deklarowane istnieją tylko w kontekście swoich bloków nie wymagają używania @ mogą być ustawiane za pomocą SET mogą być ustawiane za pomocą SELECT i SELECT INTO
Zmienne w obiektach składowanych Zliczamy byty o podanym imieniu w 2 tablicach CREATE PROCEDURE Sample(IN parametr char(30)) BEGIN DECLARE x1 CHAR(30) DEFAULT 0; DECLARE x2 CHAR(30) DEFAULT 0; SELECT count(*) into x1 FROM czlowiek where imie like parametr; SELECT count(*) into x2 FROM pracownik where i like parametr; select x1 as czlowiek, x2 as pracownik; END; mysql> call sample('jan'); +----------+-----------+ | czlowiek | pracownik | | 0 | 3 | 1 row in set (0.00 sec)
Instrukcje sterowania – programowanie a SQL
INSTRUKCJE sterowania (nie mylić z FUNKCJAMI) Funkcje sterowania są zwykłymi funkcjami SQL IF(), CASE(), IFNULL(), NULLIF() Instrukcje sterowania są przeznaczone tylko dla obiektów składowanych. Oczywiście w obiektach składowanych MOŻNA używać również funkcji sterowania IF, CASE, LOOP, LEAVE, ITERATE, REPEAT, WHILE
Instrukcja IF Instrukcja IF IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list] ... [ELSE statement_list] END IF CREATE PROCEDURE Sample(IN parametr char(30)) BEGIN IF parametr='Jan' THEN SELECT ('Janek!') as wynik; ELSE SELECT ('NIE Janek?') as wynik; END IF; END; mysql> call sample('Jan'); +--------+ | wynik | | Janek! | mysql> call sample('Janusz'); +------------+ | wynik | | NIE Janek? |
Instrukcja IF IF z wykorzystaniem bloku BEGIN-END DROP PROCEDURE IF EXISTS Sample; DELIMITER ;; CREATE PROCEDURE Sample(IN parametr char(30)) BEGIN IF parametr='Jan' THEN SELECT ('Janek!') as wynik; SELECT ('Kope lat!') as wynik; END; ELSE SELECT ('NIE Janek?') as wynik; END IF; ;; DELIMITER ;
Instrukcja CASE Instrukcja CASE mysql> call sample(1); +------------+ | JEDEN | Instrukcja CASE CASE case_value WHEN when_value THEN statement_list [WHEN when_value THEN statement_list] ... [ELSE statement_list] END CASE mysql> call sample(2); +------------+ | DWA | CREATE PROCEDURE Sample(IN parametr int) BEGIN CASE parametr WHEN 1 THEN SELECT('JEDEN'); WHEN 2 THEN SELECT('DWA'); ELSE SELECT ('MNOSTWO!!!'); END; END CASE; mysql> call sample(5); +------------+ | MNOSTWO!!! |
Instrukcje LOOP i LEAVE LOOP jest pętlą nieskończoną, z której wyjście zapewnia LEAVE nie jest to rozwiązanie "eleganckie" [begin_label:] LOOP statement_list END LOOP [end_label] mysql> call sample(3); +------------+ | (parametr) | | 3 | 1 row in set (0.00 sec) | 11 | CREATE PROCEDURE Sample(IN parametr int) BEGIN select (parametr); petla: LOOP IF parametr>10 THEN LEAVE petla; END IF; SET parametr = parametr + 1; END LOOP; END;
Instrukcje LOOP i LEAVE REPEAT jest pętlą warunkową, która wykonuje się minimum 1 raz [begin_label:] REPEAT statement_list UNTIL search_condition END REPEAT [end_label] mysql> call sample(8); +------------+ | (parametr) | | 8 | 1 row in set (0.00 sec) | 9 | | 10 | CREATE PROCEDURE Sample(IN parametr int) BEGIN REPEAT select (parametr); SET parametr = parametr + 1; UNTIL parametr>10 END REPEAT; END;
Instrukcje LOOP i LEAVE mysql> call sample(4); +------+ | (n) | | 0 | | 1 | | 2 | | 3 | 1 row in set (0.00 sec) WHILE jest typową pętlą warunkową [begin_label:] WHILE search_condition DO statement_list END WHILE [end_label] CREATE PROCEDURE Sample(IN parametr int) BEGIN DECLARE n INT; SET n = 0; WHILE n<parametr DO select (n); SET n = n + 1; END WHILE; END;
Wykorzystanie obiektów składowanych CREATE PROCEDURE MakeCzlowiek() BEGIN DECLARE ile_sylab INT; DECLARE nazwisko char(50) default ''; DECLARE imie1 char(50) default ''; DECLARE temp char(10) default ''; select 2+CAST(2*rand() as signed) into ile_sylab; while (ile_sylab>0) do select dana into temp from sylaba order by rand() limit 1; set nazwisko := concat(nazwisko,temp); set ile_sylab := ile_sylab - 1; end while; set nazwisko := concat(nazwisko,'cki'); set nazwisko := concat(ucase(substring(nazwisko,1,1)),substring(nazwisko,2)); select dana into imie1 from imie order by rand() limit 1; SELECT nazwisko; insert into czlowiek(imie, nazwisko) values (imie1, nazwisko); END; mysql> call MakeCzlowiek(); select * from czlowiek; +-------------+ | Nazanacki |
Wykorzystanie obiektów składowanych DROP PROCEDURE IF EXISTS MakeLudzie; DELIMITER ;; CREATE PROCEDURE MakeLudzie(IN ilu int) BEGIN delete from czlowiek; while (ilu>0) do call MakeCzlowiek(); set ilu := ilu - 1; end while; select count(*) as ilu_mamy_ludzi from czlowiek; END; ;; DELIMITER ; mysql> call MakeLudzie(100); +----------------+ | ilu_mamy_ludzi | | 100 | 1 row in set (0.06 sec)
TRIGGER
TRIGGER – specyficzna stored procedure TRIGGER – funkcja składowana wywoływana automatycznie, przez serwer po zaistnieniu pewnego zdarzenia TRIGGER (wyzwalacz) jest więc swego rodzaju event guardianem obiekt standardowy SQL99 update licznik set imie_ile=select count(*) from imie +----------------+ | imie | |Jan | |Tadeusz | |Piotr | |Kacper | mysql> insert into imie values ('Czesio')
Klasyfikacja TRIGGERÓW Triggery (wyzwalacze) możemy podzielić: według kryterium czasu: triggery BEFORE triggery AFTER triggery INSTEAD OF (rzadko implementowane) według kryterium rodzaju operacji (związek z type operacji, a nie poleceniem!) triggery ON INSERT (działa także w przypadku LOAD DATA) triggery ON DELETE triggery ON UPDATE według kryterium obiektu strzeżonego triggery modyfikacji danych triggery modyfikacji struktury (trigger ALTER, DROP) triggery eventowe (trigger LOGIN)
Budowa TRIGGERA Ogólna postać: Prawa (MySql): CREATE [DEFINER = { user | CURRENT_USER }] TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt delimiter | CREATE TRIGGER testref BEFORE INSERT ON test1 FOR EACH ROW BEGIN UPDATE test4 SET b4 = b4 + 1 WHERE a4 = 3; END; | delimiter ; Prawa (MySql): tworzenie triggerów wymaga praw TRIGGER dla danej tablicy (wcześniej: prawo globalne SUPER)
obiekty NEW i OLD Obiekty przechowujące wartość poprzednią i nową: create table t1 (id int, auto_increment primary key, liczba int); create table historia (z char(100), stamp timestamp) delimiter | CREATE TRIGGER moj1 AFTER UPDATE ON t1 FOR EACH ROW BEGIN INSERT INTO history(z) values (CONCAT(OLD.liczba,'->',NEW.liczba)); END; | delimiter ; update t1 set liczba=2 where id=1; insert into t1(liczba) values (222);
Obiekty OLD i NEW MySQL ułatwia wywołania obiektów poprzez nadanie im nazw delimiter | CREATE TRIGGER pensja_trigger BEFORE UPDATE ON pracownicy_table REFERENCING NEW ROW AS n, OLD ROW AS o FOR EACH ROW IF n.pensja <> o.pensja THEN --wykonaj odpowiednie działania; END IF; delimiter ;
Bezpieczniejsze tworzenie triggerów DROP TRIGGER IF EXISTS moj1; delimiter | CREATE TRIGGER moj1 AFTER UPDATE ON t1 FOR EACH ROW BEGIN INSERT INTO history (zapis) values (3); END; | delimiter ;
INDEKSY
Porównanie silników (ENGINE) w MySQL
Indeks Indeks jest pomocniczą strukturą nakładaną na tabelę (ściślej: kolumnę lub grupę kolumn), służącą polepszaniu efektywności wyszukiwania. Indeksy pogarszają efektywność operacji udpate, delete i insert. CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [index_type] ON tbl_name (index_col_name,...) [index_type] index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH}
Indeksy w MySQL Silnik MySQL używa indeksów zwłaszcza do: Generowania wyników klauzuli WHERE Eliminowania krotek (DISTINCT) Generowania wyników JOIN (warto zadbać, aby indeksy były tego samego typu i wielkości – co ma znaczenie przy indeksach tekstowych) Generowania agregatów MIN i MAX Do sortowania za pomocą ORDER BY Uwaga: MySQL używa własnego algorytmu estymacji efektywności indeksów Każdy klucz główny jest indeksowany
Indeksy typu HASH i indeksy typu B-TREE Indeksy zbudowane na drzewach są bardziej elastyczne (dlatego są domyślnym typem) Z uwagi na budowę, indeks typu HASH: Może pracować tylko dla porównań >= <= oraz = (ale za to jest bardzo szybki) Nie przyspiesza sortowania z użyciem ORDER BY (bo nie daje możliwości "znalezienia następnego") Nie może ocenić ilości danych pomiędzy granicami wyszukiwania (BETWEEN) Indeksuje jedynie całą wartość klucza
DUŻE OBIEKTY DANYCH
TEXT i BLOB BLOB (Binary Large OBject) to typ danych służący do przechowywania dużych obiektów binarnych. TEXT to duże obiekty tekstowe (używają charsetu!) CREATE TABLE picture ( ID INTEGER AUTO_INCREMENT, IMAGE BLOB, PRIMARY KEY (ID) ) ENGINE=InnoDB;
TRANSAKCJE
Transakcje Transakcje są zbiorami operacji, które chcemy uznawać za atomowe. START TRANSACTION [WITH CONSISTENT SNAPSHOT] | BEGIN [WORK] COMMIT [WORK] [AND [NO] CHAIN | [NO] RELEASE] ROLLBACK [WORK] [AND [NO] CHAIN | [NO] RELEASE] SET autocommit = {0 | 1} Uwagi: MySQL pracuje domyślnie w trybie autocommit Transkacje wymagają silnika InnoDB (lub NDB) BEGIN w transakcji nie jest tożsamy z BEGIN – END DROP, ALTER i CREATE nie są rollbackowalne Istnieje możliwość użycia SAVEPOINT i ROLLBACK TO SAVEPOINT START TRANSACTION; SELECT @A:=SUM(salary) FROM table1 WHERE type=1; UPDATE table2 SET summary=@A WHERE type=1; COMMIT;
UWAGI O PROJEKTOWANIU BAZ DANYCH
Projektowanie baz danych jako proces ETAPY: Ustalenie wymagań odbiorcy Modelowanie konceptualne Modelowanie logiczne Modelowanie fizyczne Realizacja bazy danych Testowanie i walidacja
Problem Mentalna percepcja świata rzeczywistego Model pojęciowy Schemat relacyjnej struktury danych
POSTULATY CODDA
Postulaty Codda Postulat informacyjny – dane są reprezentowane jedynie poprzez wartości atrybutów w wierszach tabel, 2. Postulat (gwarantowanego) dostępu – każda wartość w bazie danych jest dostępna poprzez podanie nazwy tabeli, atrybutu oraz wartości klucza podstawowego, 3. Postulat dotyczący wartości NULL – dostępna jest specjalna wartość NULL dla reprezentacji wartości nieokreślonej jak i nieadekwatnej, inna od wszystkich i podlegająca przetwarzaniu
Postulat dotyczący katalogu – informacje o obiektach bazy danych tworzących schemat bazy danych są na poziomie logicznym zgrupowane w tabele i dostępne w taki sam sposób jak każde inne dane. 5. Postulat języka danych – system musi dostarczać pełnego języka przetwarzania danych, który: • charakteryzuje się liniową składnią, • może być używany zarówno w trybie interaktywnym, jak i w obrębie programów aplikacyjnych, • obsługuje operacje definiowania danych (łącznie z definiowaniem perspektyw), operacje manipulowania danymi (aktualizację, takŜe wyszukiwanie), ograniczenia związane z bezpieczeństwem i integralnością oraz operacje zarządzania transakcjami (rozpoczynanie, zapis zmian i ponowny przebieg)
6. Postulat modyfikowalności perspektyw – system musi umożliwiać modyfikowanie perspektyw, o ile jest ono (modyfikowanie) semantycznie realizowane, 7. Postulat modyfikowalności danych – system musi umożliwiać operacje modyfikacji danych, musi obsługiwać operatory INSERT, UPDATE oraz DELETE, 8. Postulat fizycznej niezależności danych – zmiany fizycznej reprezentacji danych i organizacji dostępu nie wpływają na aplikacje,
9. Postulat logicznej niezależności danych – zmiany wartości w tabelach nie wpływają na aplikacje, 10. Postulat niezależności więzów spójności (niezależność integralnościowa) – więzy spójności są definiowane w bazie i nie zależą od aplikacji, 11. Postulat niezależności dystrybucyjnej – działanie aplikacji nie zależy od modyfikacji i dystrybucji bazy,
Postulat bezpieczeństwa względem operacji niskiego poziomu operacje niskiego poziomu nie mogą naruszać modelu relacyjnego i więzów spójności. Reguła nieprowadzenia "działalności wywrotowej": jeśli system jest wyposażony w interfejs niskiego poziomu (operacje na pojedynczych rekordach), nie może być użyty do prowadzenia działalności wywrotowej (np. omijania zabezpieczeń relacyjnych lub ograniczeń integralnościowych)
OBIEKTOWY MODEL DANYCH
Przeznaczenie baz danych