Baza danych to kolekcja danych umieszczonych w określony sposób w strukturach odpowiadająca założonemu modelowi danych. W potocznym ujęciu obejmuje dane oraz program komputerowy wyspecjalizowany do gromadzenia i przetwarzania tych danych. Program taki (lub zestaw programów) nazywany jest "Systemem zarządzania bazą danych" – ang. DataBase Management System (DBMS). (Ponieważ określenie "system zarządzania bazą danych" jest niewygodne w użyciu, to często samo oprogramowanie nazywa się również "bazą danych", lub DBMS'em). Bazy danych operują głównie na danych tekstowych i liczbowych, lecz większość współczesnych baz umożliwia przechowywanie danych binarnych typu: grafika, muzyka itp. Bazy danych można podzielić według struktur danych których używają: 1. bazy kartotekowe (proste) - każda tablica danych jest samodzielnym dokumentem i nie może współpracować z innymi tablicami. Do baz tego typu należą liczne programy typu - książka telefoniczna, książka kucharska, spis książek, kaset lub płyt. Wspólną cechą tych baz jest ich zastosowanie w jednym wybranym celu. 2. bazy relacyjne (złożone) - wiele tablic danych może współpracować ze sobą. Bazy relacyjne posiadają wewnętrzne języki programowania, wykorzystujące zwykle SQL do operowania na danych, za pomocą których możemy tworzyć zaawansowane funkcje obsługi danych. Relacyjne bazy danych (jak również przeznaczony dla nich standard SQL) oparte są na kilku prostych zasadach: 1. Wszystkie wartości danych oparte są na prostych typach danych. 2. Wszystkie dane w bazie relacyjnej przedstawiane są w formie dwuwymiarowych tabel (w matematycznym żargonie noszących nazwę "relacji"). Każda tabela zawiera zero lub więcej wierszy (w tymże żargonie "krotki") i jedną lub więcej kolumn ("atrybuty"). Na każdy wiersz składają się jednakowo ułożone kolumny wypełnione wartościami, które z kolei w każdym wierszu mogą być inne. 3. Po wprowadzeniu danych do bazy możliwe jest porównywanie wartości z różnych kolumn, zazwyczaj również z różnych tabel, i scalanie wierszy, gdy pochodące z nich wartości są zgodne. Umożliwia to wiązanie danych i wykonywanie stosunkowo złożonych operacji w granicach całej bazy danych. 4. Wszystkie operacje wykonywane są w oparciu o logikę, bez względu na położenie wiersza tabeli. Nie można więc zapytać o wiersze, gdzie (x=3) bez wiersza pierwszego, trzeciego i piątego. Wiersze w relacyjnej bazie danych przechowywane są w porządku zupełnie dowolnym - nie musi on odzwierciedlać ani kolejności ich wprowadzania, ani kolejności ich przechowywania. 5. Z braku możliwości identyfikacji wiersza przez jego pozycję pojawia się potrzeba obecności jednej lub więcej kolumn niepowtarzalnych w granicach całej tabeli, pozwalających odnaleźć konkretny wiersz. Kolumny te określa się jako "klucz podstawowy" (primary key) tabeli. 3. bazy obiektowe 4. strumieniowe bazy danych 5. temporalne bazy danych Podstawowe funkcje bazy danych to: projektowanie rekordów o nazwa pola o długość pola o rodzaj pola (tekstowe, liczbowe, logiczne) edycja (dopisywanie, usuwanie, poprawianie rekordów) sortowanie wyszukiwanie i selekcja danych tworzenie zapytań tworzenie raportów drukowanie UWAGA: W potocznym znaczeniu przyjęło się użycie pojęcia Baza danych określając system zarządzania danymi. Jednak w ścisłej nomenklaturze przez bazę danych rozumiemy zbiór danych zarządzany przez system zarządzania danymi. System zarządzania danymi zapewnia metody dostępu do danych. Model bazy danych - pod tym terminem kryje się zbiór zasad, którymi należy się posługiwać podczas tworzenia bazy danych. W modelu danych określa się reguły, zgodnie z którymi dane umieszcza się w strukturach. Określane są również dozwolone operacje. Definiuje się strukturę danych poprzez specyfikację reprezentacji dozwolonych w modelu obiektów (encji) oraz ich związków. W informatyce wyróżniamy główne modele baz danych: hierarchiczny model danych relacyjny model danych grafowy model danych obiektowy model danych sieci semantyczne Hierarchiczny model danych Hierarchiczny model danych jest pewnym rozszerzeniem modelu prostego, opartego na rekordach składających się z pól i zgrupowanych w plikach. W schemacie hierarchicznym wprowadza się typy rekordów i związki nadrzędny-podrzędny pomiędzy nimi. Definicja danych Typ rekordu to nazwana struktura danych, złożona ze zbioru nazwanych pól; każde pole służy do zapisu pojedynczego atrybutu obiektu opisywanego przez rekord, i charakteryzuje się określonym typem danych, np. liczba całkowita, napis, data, itp. Na ogół jedno z pól danego typu rekordu wyróżnia się jako klucz, tj. unikalny identyfikator rekordu wśród rekordów danego typu (często przydzielany dość arbitralnie, podobnie jak np. nr albumu studenta lub nr PESEL w ewidencji ludności) oraz zakłada się uporządkowanie rekordów wg. wartości jednego z pól (zwykle klucza, choć niekoniecznie). Relacja nadrzędny-podrzędny: typy rekordów tworzą strukturę drzewa, tj. każdy typ rekordu (z wyjątkiem najwyższego w hierarchii, tzw. korzenia -- root) związany jest z dokładnie jednym typem nadrzędnym. Zarazem każdy określony rekord typu podrzędnego jest związany z określonym rekordem właściwego typu nadrzędnego. Operowanie danymi Typowe operacje na danych w tym modelu to wyszukiwanie rekordów określonego typu, podrzędnych względem danego rekordu, i spełniających warunki dotyczące zawartości określonych pól; usuwanie lub dodawanie rekordów i edycja ich pól. Realizowane są poprzez funkcje lub procedury pisane w językach programowania o charakterze zazwyczaj proceduralnym, np. C. Integralność danych Podstawowe warunki integralności wynikają z samej definicji struktury danych modelu: Każdy rekord (z wyjątkiem korzenia) musi być powiązany z rekordem nadrzędnym właściwego typu; a więc np. usunięcie rekordu nadrzędnego wiąże się z usunięciem wszystkich względem niego podrzędnych. Nie można wstawić rekordu bez powiązania go z rekordem nadrzędnym. Zawartość każdego pola rekordu musi odpowiadać typowi danych z definicji danego typu rekordu. Itp. Widać, że model hierarchiczny ma wiele wspólnego ze strukturą systemu plików. Sieciowy model danych Sieciowy model danych w ogólnym zarysie niewiele odbiega od hierarchicznego. W miejsce związku nadrzędny-podrzędny pomiędzy rekordami wprowadza się w nim tzw. typ kolekcji (set), który jest złożonym typem danych pola zawierającym odniesienia do innych rekordów określonego typu. Tzn. określenie typu kolekcji polega na podaniu typu rekordu-,,właściciela'' i typu rekordów-elementów kolekcji (oraz ew. klucza porządkowania elementów). Operowanie danymi ma też charakter proceduralny: typowe operacje to wyszukiwanie rekordu na podstawie zawartości pól i/lub przynależności do danego wystąpienia typu kolekcji, i dokonywanie modyfikacji bieżącego rekordu. Warunki integralności danych, poza oczywistymi już więzami dotyczącymi zgodności zawartości pól rekordu z określeniem typu rekordu i unikalności pól kluczowych, mogą być formułowane w terminach wymogu przynależności rekordu do jakiegoś wystąpienia określonego typu kolekcji. Relacyjny model danych (RDBMS) Model relacyjny to model baz danych oparty na postulatach relacyjności. Twórcą teorii relacyjncyh baz danych jest nieżyjący już Edgar F. Codd. Postulaty te zostały opublikowane po raz pierwszy w A Relational Model of Data for Large Shared Data Banks. Dane w modelu relacyjnym są reprezentowane jako zbiór krotek, w szczególności w znormalizowanych bazach danych wszystkie one są unikalne i nie gra roli ich kolejność, a dostęp do nich jest realizowany za pomocą algebry relacji - czyli dostep do danych definiujemy poprzez operatory relacyjne takie jak: rzutowanie, selekcja, złączenie, suma, różnica, produkt kartezjański . Ograniczenie redundancji danych dokonuje się w procesie przejścia do kolejnych postaci normalnych. Zbiory danych powiązane są logicznie za pomocą encji. W ten sposób uniezależnia się widziany przez użytkownika obraz bazy danych od jej postaci fizycznej. Na modelu relacyjnym oparta jest relacyjna baza danych (RDBMS ang. Relational Database Management Systems) - baza danych, w której dane są przedstawione w postaci relacyjnej, gdzie relacja reprezentowana jest przez tablicę (tablica=relacja, stąd nazwa) a tablice są pewnym zbiorem rekordów o identycznej strukturze i wewnętrznie powiązanych za pomocą związków zachodzących pomiędzy danymi. Powoduje to ułatwienie zarządzania bazą danych w stosunku do tradycyjnego podejścia, gdzie dane są przechowywane w postaci strumienia. Takie podejście ułatwia wprowadzania zmian, zmiejszenie możliwość pomyłek, ale dzieje się to kosztem wydajności. Tradycyjną, nierelacyjną bazą danych jest BerkeleyDB. Większość współczesnych relacyjnych baz danych korzysta z jakiejś wersji języka SQL pozwalajacego wprowadzać zmiany danych w bazie i wybieranie informacji z bazy danych. Język ten opiera się na motorze bazy danych, który pozwala zadawać w języku SQL pewnego rodzaju pytania (kwerendy) i wyświetlać dane, które spełniają warunki zapytania, a także wykonywać operacje wstawiania danych, usuwania danych i ich aktualizacji. Język SQL zapewnia również zarządzanie bazą danych. Informacja o samej bazie przechowywana jest w postaci relacji (tabel) wewnątrz bazy danych. Sukces relacyjnych baz danych leży w istnieniu formalnej matematycznej struktury zwanej rachunkiem relacyjnym, pozwalającym przeprowadzić automatyczne sprawdzanie pewnych konstrukcji, gwarantującym wykonalnośc pewnych operacji i spójnośc zbiorów danych. Pierwszy dokument opisujący stosowane do dziś algorytmy zarządzania relacyjnymi bazami danych pt.: "A Relational Model of Data for Large Shared Data Banks" został opublikowany przez E. F. Codda z laboratoriów IBM w roku 1970-tym. Reguły Codd'a Model relacyjnej bazy danych został opracowany na początku lat siedemdziesiątych przez Amerykanina E.F. Codd'a, który przy jego tworzeniu oparł się na matematycznej teorii relacji i zbiorów. Dr E. F. Codd, twórca modelu relacyjnego opublikował dwuczęściowy artykuł w ComputerWorld (Codd, 1985), w którym podał 12 praw określania, kiedy baza danych jest relacyjna. Dwanaście Reguł Codd'a brzmi następująco : 1. Reguła Informacyjna. Wszystka informacja w relacyjnej bazie danych jest reprezentowana wprost i tylko w jeden sposób, jako wartości w tabelach. 2. Reguła Gwarantowanego Dostępu. Każda i wszystkie dane w relacyjnej bazie danych są logicznie dostępne poprzez nazwę tabeli, wartość klucza pierwotnego i nazwę kolumny. 3. Reguła Systematycznego Traktowania Wartości Pustych. Wartości puste (różne od pustego łańcucha znaków, łańcucha spacji i różne od zera lub innej liczby) są całkowicie wpierane przez relacyjny system zarządzania bazą danych dla reprezentacji braku informacji w sposób systematyczny (konsekwentny) niezależnie od typu danej. 4. Reguła Organizacji Dostępu w Modelu Relacyjnym. Opis bazy danych jest przedstawiany na poziomie logicznym w ten sam sposób jak dane, tak że upoważniony użytkownik może zastosować ten sam język zapytań tak w celu poznania opisu bazy jak i danych. 5. Reguła Pełności Danych Podjęzyka. System relacyjny może wspierać wiele języków, jednakże musi istnieć przynajmniej jeden, którego instrukcje tworzą wyrażenia dla dobrze zdefiniowanej składni w postaci łańcuchów znaków i są zdolne do pełnego wspierania następujących elementów: definicji danych, definicji perspektyw, manipulacji danymi (interaktywnie lub przez program), więzów integralności danych i zakresów transakcji (begin, commit i rollback). 6. Reguła Przeglądania Modyfikacji. Wszystkie modyfikacje działające na perspektywach muszą wykonywalne przez System Zarządzania Bazą Danych. 7. Reguła Wysokiego Poziomu Wstawiania, Aktualizacji i Usuwania. System musi wspierać zespół jednoczesnych działań takich jak wstawianie, aktualizacja i usuwanie danych. 8. Reguła Fizycznej Niezależności Danych. Programy aplikacyjne lub akcje wykonywane na terminalu pozostają logicznie nienaruszone w przypadku zmian dokonywanych w reprezentacji pamięci fizycznej lub metod dostępu. 9. Reguła Logicznej Niezależności Danych. Modyfikacje w logicznej strukturze bazy danych mogą być wykonywane bez wyrejestrowywania się istniejących użytkowników czy zamykania istniejących programów. 10. Reguła Niezależności Integralności. Ograniczenia integralności specyficzne dla konkretnej relacyjnej bazy danych muszą być definiowalne w podjęzyku relacyjnym i przechowywane w schemacie bazy a nie w programie aplikacyjnym. Minimum dwa ograniczenia integralności muszą być wpierane: • integralność encji: żaden z elementów składowych klucza pierwotnego nie może zawierać wartości pustej, • integralność referencyjna: dla każdej różnej, nie pustej wartości klucza obcego musi odpowiadać odpowiednia wartość klucza pierwotnego z tej samej domeny 11. Reguła Niezależności Dystrybucji. Niezależność dystrybucji wymusza, że użytkownicy nie powinni martwić się kiedy baza danych jest dystrybuowana 12. Reguła Braku Podwersji. Dostęp na niskim poziomie albo na poziomie rekordu nie może być zdolny do naruszenia systemu, ominięcia reguł integralności lub ograniczeń zdefiniowanych na wyższych poziomach Do 12 reguł istnieje uzupełnienie znane jako Reguła zero: Dla każdego systemu, który uważany jest za relacyjny musi istnieć możliwość zarządzania danymi wyłącznie poprzez jego relacyjne możliwości Normalizacja baz danych Normalizacja baz danych jest to proces mający na celu eliminacje powtarzających się danych w relacyjnej bazie danych. Główna idea polega na trzymaniu danych w jednym miejscu, a w razie potrzeby linkowania do danych. Taki sposób tworzenia bazy danych zwiększa bezpieczeństwo danych i zmniejsza ryzyko powstania niespójności (w szczególności problemów anomalii). Pierwsza postać normalna W poszczególnych tabelach wyeliminuj powtarzające się grupy. Dla każdego zestawu danych pokrewnych utwórz oddzielną tabelę. Dla każdego zestawu danych pokrewnych określ klucz podstawowy. Do przechowywania podobnych danych w jednej tabeli nie należy używać wielu pól. Na przykład rekord służący do śledzenia pozycji inwentarzowej, która może pochodzić z dwóch różnych źródeł, może zawierać pola Kod sprzedawcy 1 oraz Kod sprzedawcy 2. Co się zdarzy po dodaniu trzeciego sprzedawcy? Dodawanie pola nie dostarcza odpowiedzi. Wymaga to modyfikacji programu i tabel oraz nie umożliwia obsługi zmieniającej się dynamicznie liczby sprzedawców. Zamiast tego należy umieścić wszystkie informacje o sprzedawcach w oddzielnej tabeli o nazwie Sprzedawcy, a następnie połączyć magazyn ze sprzedawcami za pomocą klucza z numerem pozycji, albo sprzedawców z magazynem za pomocą klucza z kodem sprzedawcy. Druga postać normalna Utwórz oddzielne tabele dla zestawów wartości, odnoszących się do wielu rekordów. Ustal powiązania tabel za pomocą klucza obcego. Rekordy nie powinny zależeć od niczego innego niż klucz podstawowy tabeli (w razie potrzeby może to być klucz złożony). Rozważmy, na przykład, adres klienta w systemie księgowym. Obecność adresu konieczna jest w tabeli Klienci, ale również w tabelach Zamówienia, Wysyłka, Faktury, Należności i Inkaso. Zamiast przechowywać adres w postaci wpisu w każdej tabeli, przechowuje się go w jednym miejscu: albo w tabeli Klienci, albo w oddzielnej tabeli Adresy. Trzecia postać normalna Wyeliminuj pola, które nie zależą od klucza. Wartości rekordu, które nie są częścią jego klucza, nie należą do tabeli. Zazwyczaj, jeśli zawartość grupy pól odnosi się do więcej niż jednego rekordu tabeli, należy rozważyć umieszczenie tych pól w oddzielnej tabeli. Na przykład w tabeli Rekrutacja pracowników może znajdować się nazwa i adres uczelni, którą ukończył kandydat. Do korespondencji seryjnej potrzebna jest jednak kompletna lista uczelni. Jeśli informacje o uczelniach przechowywane są w tabeli Kandydaci, nie ma możliwości wyświetlenia listy uczelni bez aktualnych kandydatów. Utwórz oddzielną tabelę Uczelnie i połącz ją z tabelą Kandydaci za pomocą klucza z kodem uczelni. WYJĄTEK: Stosowanie reguł trzeciej postaci normalnej, chociaż teoretycznie wskazane, nie zawsze jest praktyczne. Chcąc wyeliminować wszystkie możliwe wewnętrzne zależności pomiędzy polami tabeli Klienci, należy utworzyć oddzielne tabele dla miast, kodów pocztowych, przedstawicieli handlowych, klas klienta i innych czynników, które mogą być zduplikowane w wielu rekordach. Normalizacja oznacza teoretycznie poprawę wydajności. Jednak wiele mniejszych tabel może spowodować spadek wydajności lub brak możliwości otwarcia pliku i przekroczenie pojemności pamięci. Bardziej realne może okazać się zastosowanie trzeciej postaci normalnej tylko do często zmienianych danych. Pozostawiając niektóre pola zależne, zmień projekt aplikacji tak, aby po zmianie dowolnego pola wymagała od użytkownika sprawdzenia wszystkich pól pokrewnych. SQL SQL (ang. Structured Query Language) to strukturalny język zapytań używany do tworzenia, modyfikowania baz danych oraz do umieszczania i pobierania danych z baz danych. Formy SQL-a Z technicznego punktu widzenia, SQL jest podjęzykiem danych. Oznacza to, że jest on wykorzystywany wyłącznie do komunikacji z bazą danych. Nie posiada on cech pozwalających na tworzenie kompletnych programów. Jego wykorzystanie może być trojakie i z tego względu wyróżnia się trzy formy SQL-a: 1. SQL interakcyjny lub autonomiczny wykorzystywany jest przez użytkowników w celu bezpośredniego pobierania lub wprowadzania informacji do bazy. Przykładem może być zapytanie prowadzące do uzyskania zestawienia aktywności kont w miesiącu. Wynik jest wówczas przekazywany na ekran, z ewentualną opcją jego przekierowania do pliku lub drukarki. 2. Statyczny kod SQL (Static SQL) nie ulega zmianom i pisany jest wraz z całą aplikacją, podczas której pracy jest wykorzystywany. Nie ulega zmianom w sensie zachowania niezmiennej treści instrukcji, które jednak zawierać mogą odwołania do zmiennych lub parametrów przekazujących wartości z lub do aplikacji. Statyczny SQL występuje w dwóch odmianach. 1. Embedded SQL (Osadzony SQL) oznacza włączenie kodu SQL do kodu źródłowego innego języka. Większość aplikacji pisana jest w takich językach jak C++ czy Java, jedynie odwołania do bazy danych realizowane są w SQL. W tej odmianie statycznego SQL-a do przenoszenia wartości wykorzystywane są zmienne. 2. Język modułów. W tym podejściu moduły SQL łączone są z modułami kodu w innym języku. Moduły kodu SQL przenoszą wartości do i z parametrów, podobnie jak to się dzieje przy wywoływaniu podprogramów w większości języków proceduralnych. Jest to pierwotne podejście, zaproponowane w standardzie SQL. Embedded SQL został do oficjalnej specyfikacji włączony nieco później. 3. Dynamiczny kod SQL (Dynamic SQL) generowany jest w trakcie pracy aplikacji. Wykorzystuje się go w miejsce podejścia statycznego, jeżeli w chwili pisania aplikacji nie jest możliwe określenie treści potrzebnych zapytań - powstaje ona w oparciu o decyzje użytkownika. Tę formę SQL generują przede wszystkim takie narzędzia jak graficzne języki zapytań. Utworzenie odpowiedniego zapytania jest tu odpowiedzią na działania użytkownika. Wymagania tych trzech form różnią się i znajduje to odbicie w wykorzystywanych przez nie konstrukcjach językowych. Zarówno statyczny, jak i dynamiczny SQL uzupełniają formę autonomiczną cechami odpowiednimi tylko w określonych sytuacjach. Większość języka pozostaje jednak dla wszystkich form identyczna. Składnia SQL Użycie SQL, zgodnie z jego nazwą, polega na zadawaniu zapytań do bazy danych. Zapytania można zaliczyć do jednego z dwóch głównych podzbiorów: SQL DML (ang. Data Manipulation Language, czyli Język Manipulacji Danymi), SQL DDL (ang. Data Definition Language, czyli Język Definicji Danych). Instrukcje SQL w obrębie zapytań tradycyjnie zapisywane są wielkimi literami, jednak nie jest to wymóg. Każde zapytanie w SQL-u musi kończyć się znakiem ";" (średnik). Dodatkowo, niektóre interpretery SQL (np. psql w przypadku PostgreSQL), używają swoich własnych instrukcji, spoza standardu SQL, które służą np. do połączenia się z bazą, wyświetlenia dokumentacji, itp. DML DML służy do operacji na danych - do ich umieszczania w bazie, kasowania, przeglądania, zmiany. Najważniejsze polecenia z tego zbioru to: SELECT - pobranie z bazy danych, INSERT - umieszczenie danych w bazie, UPDATE - zmiana danych, DELETE - usunięcie danych z bazy. Dane tekstowe podawane muszą być zawsze w formie ograniczonej znakami pojedynczego cudzysłowu ('). DDL Dzięki DDL natomiast, można operować na strukturach, w których te dane są przechowywane - czyli np. dodawać, zmieniać i kasować tabele lub bazy. Najważeniejsze polecenia tej grupy to: CREATE (np. CREATE TABLE, CREATE DATABASE, ...) - utworzenie struktury (bazy, tabeli, indeksu, itp.), DROP (np. DROP TABLE, DROP DATABASE, ...) - całkowite usunięcie struktury, ALTER (np. ALTER TABLE ADD COLUMN ...) - zmiana struktury (dodanie kolumny do tabeli, zmiana typu danych w kolumnie tabeli). Przykładowe zapytania Przykładowe użycie wyżej wymienionych rodzajów zapytań. SELECT * FROM pracownicy WHERE pensja > 2000 ORDER BY staz DESC; Wyświetla z tabeli pracownicy (FROM pracownicy) wszystkie kolumny (*) dotyczące tych pracowników, których pensja jest większa niż 2000 (WHERE pensja > 2000) i sortuje wynik malejąco według stażu pracy (ORDER BY staz DESC). INSERT INTO pracownicy (imie, nazwisko, pensja, staz) VALUES ('Jan', 'Kowalski', 5500, 1); Dodaje do tabeli pracownicy (INTO pracownicy) wiersz (rekord) zawierający dane pojedynczego pracownika. UPDATE pracownicy SET pensja = pensja * 1.1 WHERE staz > 2; Podnosi o 10% (SET pensja = pensja * 1.1) pensję pracownikom, których staż jest większy niż 2 (np. lata). DELETE FROM pracownicy WHERE imie = 'Jan' AND nazwisko = 'Kowalski'; Usuwa z tabeli "pracownicy" wiersz (rekord) dotyczący pracownika o imieniu "Jan" i nazwisku "Kowalski". CREATE TABLE pracownicy (imie varchar(255), nazwisko varchar(255), pensja float, staz int); Tworzy tabelę "pracownicy" zawierającą tekstowe (varchar - zmiennej długości pole tekstowe) pola "imię" i "nazwisko", o maksymalnej długości 255 znaków, zapisaną za pomocą liczby rzeczywistej (float od ang. floating point) pensję oraz zapisany za pomocą liczby całkowitej (int od ang. integer) staż. DROP TABLE pracownicy; Usuwa z bazy całkowicie tabelę "pracownicy". ALTER TABLE pracownicy ADD COLUMN dzial varchar(255); Dodaje do struktury tabeli "pracownicy" kolumnę "dzial" (dział), jako pole tekstowe o długości max. 255 znaków. Więcej na: http://pl.wikipedia.org/.