Структура на базата данни

След като сме наясно, че къде и с помощта на каква база данни ще съхраняваме информацията, идва момента си си отговорим на въпроса какво ще съхраняваме.

Нека в нашия случай да се опитаме да съставим схемата на една складова база данни. Примерът ще бъде максимално опростен и ще има за цел да покаже някои принципи в съставянето на базите данни, а не каква е необходимата складова информация.

Нека приемем, че наличната до сега информация е била във вида на документи, съдържащи следната информация:

  1. На кого принадлежи стоката
  2. Вид на стоката
  3. Кога е доставена в склада
  4. Кой я е приел
  5. Колко голяма е доставката
  6. Срок на годност

Текущо бихме желали да получаваме следната информация:

  1. Какви видове стоки имаме в наличност
  2. Какво количество имаме от всеки вид
  3. Колко стоки са с изтекъл срок на годност
  4. Кой служител какви стоки е приел
  5. Списък на доставчиците
  6. Списък на количествата от всеки доставчик

Очевидно, всичко, което се съдържа в документацията трябва да намери място и в базата данни. За всяка единица информация, съдържаща се в документите ние трябва да отделим по едно поле (колонка) в нашите таблици. Имаме много различни варианти за организация на информацията, които бихме могли да използваме. Най-простият от тях (и най-очевидният) е да имаме една таблица, съдържаща всичката информация, която постъпва.

Нека именоваме всяка единица информация с името на полето, в което ще я записваме. Тогава най-простият вариант на нашата база данни ще трябва да съдържа следните полета:

Ето една примерна таблица със такава структура:

Sobstwenik Wid Pristignalo Priel Kolichestwo Godnost
ЕТ “Петър Христов” Хляб 12.01.2003 Петър Иванов 6 13.01.2003
ХЕИ- Складове Лаб. Стъклария 13.01.2003 Стойко Килиферов 2 13.01.2015
MIC- Компютри Кутии 13.01.2003 Стойко Килиферов 8 13.01.2015
ХЕИ- Складове Химикали 14.01.2003 Петър Иванов 2 14.01.2004
ХЕИ- Складове Химикали 14.01.2003 Стойко Килиферов 2 14.01.2004
MIC- Компютри Монитори 14.01.2003 Петър Иванов 15 14.01.2008
MIC- Компютри Монитори 14.01.2003 Петър Иванов 3 14.01.2008
MIC- Компютри Принтер 14.01.2003 Петър Иванов 2 14.01.2004
ЕТ “Петър Христов” Хляб 03.02.2003 Петър Иванов 6 04.02.2003
ООД- Герчо Стоянов & Co Моливи 04.02.2003 Стойко Килиферов 15 04.02.2005
Паркстрой Косачка 04.02.2003 Стойко Килиферов 1 04.02.2015
Паркстрой Инструменти 04.02.2003 Петър Иванов 15 04.02.2015
ЕТ- “Продан Михайлов” Хартия 05.02.2003 Стойко Килиферов 11 05.02.2004

Обърнете внимание, че имената на полетата (колонките) са написани на латиница. Това е така, защото не всяка база данни позволява използването на кирилица в наименованията на обектите в нея, а и толерантността на познатите ми до сега операционни системи (Windows и Linux) стига до там, че в един прекрасен момент да се чудя как да погледна какво се крие зад нещо дето съм го наименовал на кирилица, а го виждам изписано с някакви неразбираеми знаци. За да се избягват такива неприятности бих ви посъветвал да наименовате полетата така както си желаете, но имената да ги пишете на латиница. Имената на колоните могат да не се показват на потребителя, така че те си остават само за вас като програмисти.

Всеки вид стока си има свои изисквания при съхранението. Затова добре би било нашата база данни да съдържа и тази информация. Това налага да разполагаме с информация за типизацията на стоките (Не ме питайте от къде да я вземете! Сега пишем програма и предполагаме, че тя ни е под ръка.), но за сега няма да включваме тази информация в нашия пример.

Първо, добре е да се опитаме да направим оценка на обема информация, който ще трябва да обработваме с нашата база данни. Нека да допуснем, че приведената таблица е само една малка извадка от бележките, получени в рамките на един месец. Ако месечното количество на стоки постъпили в склада е около 300 (по 10 на ден) и необходимият срок за съхранение на информацията е 2 години след напускането на стоката то бихме могли да очакваме, че нашата база данни би трябвало да се справя с около 6000 записа. Това число в никакъв случай не е голямо и която и да е от съществуващите бази данни би могла да се справи с него. (Какви са възможностите на определен тип база данни можете да прочетете в упътването й)

Следва да определим типа на полетата в нашата база данни.

Използваните типове са с имена като тези в Java. Всяка база данни си има предварително дефинирани типове информация, които са описани в нейната документация. Ако базата данни е SQL съвместима, то ето как биха изглеждали типовете информация в нашия случай:

Някои от типовете информация изискват да се укаже каква е дължината на полето в базата данни, т.е. Колко единици информация ще можем да записваме в него. При нас това са полетата от типа VARCHAR. Ето списъка с типовете написан за последен път с всичката необходима информация:

Нека наименуваме нашата таблица “Sklad”.

Разглеждайки извадката от информация, която би трябвало да се съдържа можем да забележим, че имаме полета, където информацията много често се повтаря: Sobstwenik и Priel, например. За да избегнем повторното записване можем да използваме една допълнителна таблица, която да съдържа имената на собствениците и още една, която да съдържа имената на служителите приемащи стоката. В тези таблици на всяко едно име ще е присвоен по един номер, така че ние в нашата основна таблица ще записваме само него, а ако ни е нужен текста, който се крие за този номер ще поглеждаме в таблицата с имената.

Ето как би изглеждало разпределението на информацията с нашите примерни данни.

Sobstwenik Wid Pristignalo Priel Kolichestwo Godnost
1 Хляб 12.01.2003 1 6 13.01.2003
2 Лаб. Стъклария 13.01.2003 2 2 13.01.2015
3 Кутии 13.01.2003 2 8 13.01.2015
2 Химикали 14.01.2003 1 2 14.01.2004
2 Химикали 14.01.2003 2 2 14.01.2004
3 Монитори 14.01.2003 1 15 14.01.2008
3 Монитори 14.01.2003 1 3 14.01.2008
3 Принтер 14.01.2003 1 2 14.01.2004
1 Хляб 03.02.2003 1 6 04.02.2003
4 Моливи 04.02.2003 2 15 04.02.2005
5 Косачка 04.02.2003 2 1 04.02.2015
5 Инструменти 04.02.2003 1 15 04.02.2015
6 Хартия 05.02.2003 2 11 05.02.2004

Забележете наименованията на полетата в таблиците. Полетата с еднакво значение са с еднакви имена, както в таблиците първото поле е с името на съдържанието на таблицата + ID. Това е само конвенция за образуването на имената. Не е задължително, но е препоръчително, защото се улеснява по-нататъшното четене на програмата, която ще пишем за работа с базата данни.

Можем още да добавим и една таблица, съдържаща типизацията на стоките, за да можем в полето Wid да пишем също само едно число. Също така, добавянето на колонка с номер на документа в таблицата Sklad би било полезно. Тези неща ги оставям на вас за експериментиране. Ние продължаваме по-нататък.

Създаване на таблиците в базата данни

За сега нашата база данни е регистрирана в ODBC или е създадена с помощта на hsqldb мениджъра (или по какъвто и да било друг начин). С помощта на нашите програмки HsqldbDemo и AccessDemo можем да установяваме връзка с тях. Време е да създадем структурата на базата данни. Създаването на отделните таблици може да става както със съответния мениджър, така и с помощта на SQL. Тъй-като не се опитваме да разучаваме работата с кой да е мениджър ще демонстрираме създаването на таблиците с помощта на SQL и JDBC. Можете да използвате която и да е от примерните програмки. Това което ще следва са само фрагменти от програмата, които трябва да се вмъкнат на съответното място.

След като сме установили връзка с нашата база данни с помощта на ред от вида:

Connection conn=DriverManager.getConnection ("jdbc:hsqldb:/hsqldb/data/produkti","sa","");

можем да започнем да изпращаме команди към нея. За целта трябва да създадем запитване и да го изпратим. Това става по следния начин:

void createDB(Connection conn){
   try{
   Statement stmt=conn.createStatement();

     String query="CREATE TABLE Sklad (DostawchikID INT,";
           query+="Wid VARCHAR(80),";
           query+="Pristignalo DATE,";
           query+="SluzitelID INT,";
           query+="Kolichestwo INT,";
           query+="Godnost DATE)";

     stmt.executeQuery(query);

     query="CREATE TABLE Dostawchici (DostawchikID INT IDENTITY,";
     query+=" Dostawchik VARCHAR(80))";

     stmt.executeQuery(query);

     query="CREATE TABLE Sluziteli (SluzitelID INT IDENTITY,";
     query+="                       Sluzitel VARCHAR(80))";

     stmt.executeQuery(query);

     stmt.close();
   }catch(Exception e){
     e.printStackTrace();
   }
}

Редът:

Statement stmt=conn.createStatement();

създава комуникационен обект, който ще ни служи за обменяне на информация с базата данни. Изпращането на командите става с помощта на редовете:

stmt.executeQuery(query);

Класът Statement ви предлага още много вариации на методите execute. Всеки от тях си има своето приложение, но най-простият начин да изпратим команда до сървъра е показаният по-горе. Параметърът query съдържа команди на езика SQL (по точно на диалекта приложим за вашата база данни). В случая ние само създаваме таблиците, за съхранение на информация в нашата база данни.

Отново една условност: всички команди, които принадлежат на SQL се пишат с главни букви. Не е задължително, но се препоръчва!

Виждате, че SQL изисква доста “разказвателно” да си изложите желанията:

CREATE TABLE Име_На_Таблицата (Име_На_Колона Тип_на_Колоната Настройки, Име_На_Колона Тип_на_Колоната Настройки, ...)

Ето това е граматиката на израза за съставяне на таблица. Просто изреждаме това, което желаем. По интересно е използването на Настройката IDENTITY. Колоните с този параметър трябва да бъдат целочислени и тяхната стойност се променя автоматично. Всеки нов ред в таблица с такава колона притежава нова стойност за това поле, с едно по-голяма от тази на полето от предишния ред. Стойността до която се е стигнало до момента зависи от самата таблица. Дори и да изтрием някой ред стойностите продължават да нарастват от там до където са стигнали при предното добавяне на информация (нещо като номерата на кочаните с фактури, билети и др. финансови документи). Такива полета, обикновено се използват за уникално обозначаване на записите в една таблица. Ако си спомняте, нашата нужда беше точно такава в случая с таблиците Dostawchici и Sluziteli. Разбира се, тук трябва да се съобразим с максималния брой записи, който ще трябва да се обозначават с помощта на такива полета. Ако размерът на полето което ще използваме е 8 бита, то след 256 нараствания полето отново ще започне да се повтаря. Следователно трябва типът на полето да отговаря на нашите нужди. Обикновено се използват идентификатори с размер 32 бита, като по този начин можем да записваме около 2 милиарда записа.

Записване на информация в базата данни

След като сме създали таблиците, вече можем да помислим за тяхното последователно пълнене. Имаме два проблема за решаване:

  1. Трябва да намерим начин да въведем съществуващата вече информация или необходимия минимум от нея (определя се от нуждите на вашия клиент).
  2. Трябва да направим удобен интерфейс за текущо въвеждане на информацията.

Начинът за въвеждане на необходимото начално количество информация зависи от вида на натрупаната информация. Ако всичко, което имаме е един куп бележки, вероятно най-удобно сте бъде първо да се реши вторият проблем, и после да се въведе информацията.

Ако информацията е събрана на някакъв електронен носител много по-удобно би било информацията да се въведе по програмен начин. Необходимо е да сме наясно с формата на предоставената информация. Тогава въвеждането на тази информация би могло да означава писането на програма, която да преработи входните данни и да запише всичко в базата данни.

Ако източник на вашия електронен носител е друга база данни, добре е да се има предвид, че повечето бази данни предоставят възможност за експортиране на наличната информация в някакъв стандартен вид, например набор от SQL команди или във вид на CSV (Comma Separated Values) формат. Тогава, ако вашата база данни разполага с някакъв стандартен интерфейс проверете дали пък той няма възможности за импортиране на тази информация.

Тук ще разгледаме само основния начин за добавяне на записи към една SQL база данни. Отново ще използваме обект от клас Statement за да изпратим команди до сървъра. Ето ги и самите команди:

INSERT INTO Sklad VALUES(1,'Хляб','2003-01-02',1,6,'2003-01-13')
INSERT INTO Sklad VALUES(2,'Лаб. Стъклария','2003-01-13',2,2,'2015-01-13')
INSERT INTO Sklad VALUES(3,'Кутии','2003-01-13',2,8,'2015-01-13')
INSERT INTO Sklad VALUES(2,'Химикали','2003-01-14',1,2,'2004-01-14')
INSERT INTO Sklad VALUES(2,'Химикали','2003-01-14',2,2,'2004-01-14')
INSERT INTO Sklad VALUES(3,'Монитори','2003-01-14',1,15,'2008-01-14')
INSERT INTO Sklad VALUES(3,'Монитори','2003-01-14',1,3,'2008-01-14')
INSERT INTO Sklad VALUES(3,'Принтер','2003-01-14',1,2,'2004-01-14')
INSERT INTO Sklad VALUES(1,'Хляб','2003-02-03',1,6,'2003-02-04')
INSERT INTO Sklad VALUES(4,'Моливи','2003-02-04',2,15,'2005-02-04')
INSERT INTO Sklad VALUES(5,'Косачка','2003-02-04',2,1,'2015-02-04')
INSERT INTO Sklad VALUES(5,'Инструменти','2003-02-04',1,15,'2015-02-04')
INSERT INTO Sklad VALUES(6,'Хартия','2003-02-05',2,11,'2004-02-05')

Обърнете внимание на начина на записване на датата: Година-Месец-Дата. Това е като стандарт при работа с бази данни. Някой позволяват и други формати за задаване на самата дата, но това е специфична особеност. SQL изисква този формат.

По подобен начин зареждаме информацията и в останалите две таблици. Особеното при тях е, че имаме поле, което би трябвало само да си променя стойностите. Можем да използваме три начина за добавяне на записи към таблици с такива полета:

  1. Ако използваме INSERT с неговия пълен синтакс можем да напишем:
  2. INSERT INTO Dostawchici (Dostawchik) VALUES('ЕТ “Петър Христов”')

    ...

    и така нататък докато добавим всички доставчици. Частта (Dostawchik) позволява да укажем в кои полета от базата данни ще записваме по нещо. Останалите полета ще получат стойност по подразбиране. Тази стойност за различните типове полета е различна. Полето може да е празно (NULL) или да има някаква предварително определена при създаването на таблицата стойност. В нашия случай изпускаме полето DostawchikID и то ще получи стойност по подразбиране, която е следващия по големина номер. В този случай, първо трябва да запълним тази таблица и после като знаем на какви са стойностите на DostawchikID за всеки един ред да попълним основната си таблица Sklad с тях.

  3. Можем да използваме следното:
  4. INSERT INTO Dostawchici VALUES(1,'ЕТ “Петър Христов”')

    ...

    и така нататък докато добавим всички доставчици. Тук ние си задаваме номерата на нашите доставчици. Това е допустимо, защото полетата са уникални и не нарушават правилата за стойностите в това поле.

  5. И последно, можем да използваме:
  6. INSERT INTO Dostawchici VALUES(NULL,'ЕТ “Петър Христов”')

    ...

    и така нататък докато добавим всички доставчици. NULL ще рече, че не искаме да въвеждаме нищо в полето DostawchikID и го оставяме да бъде с неговата стойност по подразбиране.

За предпочитане е втория начин, тъй-като данните не са твърде много и можем да им определим автоматичните стойности.

Задача: Напишете програма, която да въведе всички стойности от посочения пример в нужните таблици. Използвайте база данни по ваш избор.

Променете програмата така, че да работи с другата база данни.

Когато работите с hsqldb проконтролирайте правилността на вашите действия.

Можете да се консултирате с тази част.

След като изпълните тази задача можем да преминем към

Извършване на запитвания и редактиране на базата данни