Что делать если во время работы программы необходимо сохранить информацию, которая может понадобится в дальнейшем, в том числе при следующих запусках программы? Или если необходимо хранить большие массивы информации, а также иметь возможность получать выборки из хранимых данных во время работы программы. Или необходимо обмениваться информацией между несколькими запущенными сеансами программы? Можно конечно попытаться сохранять данные в текстовый файл, или в Excel и т.п. Но все это будет работать медленно на больших объемах. Плюс неудобный (трудоемкий) доступ к данным (необходимо писать довольно много кода). А при попытках выполнять операции записи и чтения в подобных файлах несколькими сеансами одновременно у вас всегда будут проблемы.
Но есть другой путь — создать базу данных! И в NOMAD есть инструмент, с помощью которого это можно сделать, а именно класс TDataBases. Который позволяет создавать и подключаться к базам данных в формате MS Access. А с помощью языка SQL (DDL, DML) диалект MS Access вы имеете те же возможности по созданию и манипуляции базой данных, которые бы у вас были, если бы вы запустили сам MS Access. Только в нашем случае все это можно делать прямо из кода программы. Причем для работы этого механизма устанавливать MS Access в системе не нужно, т.к. все необходимые инструменты встроены в Windows.
В данной статье я не буду подробно описывать язык SQL для этого есть много других книг и статей, которые можно найти в интернете. Например, http://www.sql.ru/docs/sql/u_sql/index.shtml Но некоторые примеры основных операций будут ниже продемонстрированы. Необходимо также учитывать , что не все (но большинство) команды и конструкции найденные в интернете будут работать в нашем случае, т.к. каждая база данных имеет свои особенности, поэтому некоторые команды которые работают в MS SQL в MS Access работать не будут.
Методы и свойства класса:
Property QueryText :string; — этому параметру необходимо присваивать текст запроса или команды к базе данных на языке SQL.
constructor Create(Parent:TForm); — конструктор класса, создает экземпляр класса, в качестве параметра необходимо передавать ссылку на форму, в случае если у вас одна форма главная то пишем DB := TDataBases.Create(self); Можно передавать значение nil, но в таком случае вы не сможете выводить в таблицу данные запросов.
destructor Destroy;-деструктор класса необходимо вызывать по окончанию работы с объектом класса, чтобы освободить память выделенную под него. Лучше использовать метод DB.FREE, вместо DB.Destroy.
Function ConnectToBase(pFileName: string): Boolean; — подключение к базе данных, необходимо вызывать этот метод каждый раз после конструктора. В качестве параметра методу передаем полный путь к файлу базы данных, если метод не обнаружит такого файла по указанному пути, то он создаст его сам.
Procedure MakeQuery; — выполнить запрос к базе данных, данную команду необходимо вызывать если в тексте запроса вы пытаетесь получить выборку данных из базы. Т.е. это конструкция SELECT * FROM. Если попытаться выполнить запрос в результате которого никаких данных не возвращается, то метод вернет ошибку.
Procedure SendCommand; — отправить команду базе данных. Данную команду необходимо вызывать для манипуляции данными в базе. (создание/удаление таблиц, колонок, вставка строк в таблицы, присвоение значений полям и т.д.). Метод нельзя использовать с конструкцией SELECT * FROM.
Также, если в запросе вы используете параметры, то присвоить им значения можно с помощью методов:
Procedure SetParametr(ParametrName: string; ParametrValue: variant); — где ParametrName — имя параметра, а ParametrValue — значение параметра.
Procedure SetParametrByIndex(Index:cardinal;ParametrValue: variant); — данная процедура присваивает параметру с индексом Index значение переданное в параметре ParametrValue. Нумерация параметров начинается с 0.
Приведем пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Procedure BaseWork; var DB1 :TDataBases; begin DB1 := TDataBases.Create(self);//создали экземпляр DB1 класса TDataBases DB1.ConnectToBase('C:\DBFile.mdb');//подключились к базе данных DB1.QueryText := 'select * from TestTable where Name = :p1'; //задали текст запроса, тут мы хотим получить выборку строк по всем колон //кам из таблицы с именем TestTable, причем мы задаем ограничение, что зн //ачение в поле с именем Name должно быть равно :p1, где p1 это параметр, // значение которому мы должны присвоить. Т.е. для того чтобы указать баз //е данных что мы передаем ей параметр необходимо перед ним поставить сим //вол ':' (двоеточие) DB1.SetParametr('p1', 'balkon'); //присваиваем параметру p1 значение 'balkon' DB1.SetParametrByIndex(0,'balkon');//или можно присвоить его так. DB1.MakeQuery; //отсылаем запрос базе данных и в ответ получаем выборку end; |
Procedure ClearParametrs; — очищает ранее заполненную таблицу параметров.
Функции для работы с результатом запроса:
Function First: Boolean; — перейти к первой записи выборки, возвращает истину, если операция выполнена успешно и ложь, если такой записи нет.
Function Next: Boolean; — перейти к следующей записи выборки, возвращает истину, если операция выполнена успешно и ложь, если такой записи нет.
function Prior: Boolean; — перейти к предыдущей записи выборки, возвращает истину, если операция выполнена успешно и ложь, если такой записи нет.
Function GetFieldValue(FieldName: string): variant; — возвращает значение поля с именем FieldName в текущей строке. Перед использованием необходимо спозиционироваться на строке с помощью команд First,Next и т.д.
Function GetFieldValueByIndex(_Index: cardinal): variant; — возвращает значение поля с номером _Index в текущей строке. Перед использованием необходимо спозиционироваться на строке с помощью команд First,Next и т.д. Нумерация полей начинается с 0.
Function GetFieldNameByIndex(_Index: cardinal): string; — возвращает имя колонки с номером _Index. Нумерация полей начинается с 0.
Function GetFieldCount: cardinal; — возвращает количество колонок в выборке.
Рассмотренных функций достаточно, чтобы манипулировать структурой базы данных и ее наполнением, а также делать выборки данных из нее.
Результаты запроса также можно выводить в табличную часть помещенную на главную форму программы. Для этого необходимо двойным щелчком на форме вызвать диалоговое окно выбора компонента для вставки и выбрать из списка компонент Table
Манипулировать этой таблицей из кода программы нельзя. Но можно подключить к ней экземпляр класса TDataBases, после чего при каждом выполнении команды MakeQuery в таблице будет отображаться результирующая выборка.
Также существует возможность проверить наличие в базе таблицы с определенным именем:
Function TabExists(TableName: string): Boolean; — возвращает True если таблица с именем TableName есть в базе данных.
Function ColExists(TableName, ColumnName: string): Boolean; — Возвращает True, если колонка с именем ColumnName существует в таблице TableName. Если нет и самой таблицы функция также вернет false.
Function GetTablesList(var val: TStringList): Boolean; — если функция выполнена успешно, то в параметр val помещаются названия всех таблиц, которые есть в подключенной базе данных.
Function GetColumnsList(TableName: string; var val: TStringList): Boolean; — возвращает в параметр val список наименований колонок таблицы с именем TableName.
Остальные функции класса созданы для тех кому лень писать запросы, но без запросов все равно не обойтись.
Рассмотрим их на примере. Создадим таблицу Payments которая изображена на картинке выше и добавим в нее несколько строк.
function AddTable(TableName: string; Columns: TStringList): Boolean; — функция добавляет в базу данных таблицу с именем TableName и колонками переданными в параметре Columns.
function AddColumn(TableName: string; ColumnName, DataType: string) : Boolean; — функция добавляет колонку в таблицу с именем TableName. Где ColumnName — имя новой колонки. DataType — тип данных новой колонки. Имя колонки не может совпадать с ключевыми словами языка SQL, если такое случится, то база данных вернет сообщение о синтаксической ошибке.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
var DB : TDataBases; Procedure CreateBase; var Columns: TStringList; begin DB := TDataBases.Create(self);//создаем экземпляр класса, передаем //ему ссылку на форму, на которой находится таблица, в которой мы //будем показывать результаты наших запросов DB.ConnectToBase('C:\DBFile.mdb'); //подключаемся к базе данных, //если такого файла нет, он будет создан автоматически. DB.ConnectToTable('Table1');//подключаемся к таблице Table1, которая //расположена на форме if not DB.TableExist('Payments') then //проверяем, если такой таблицы begin //в базе данных еще нет, то: Columns := TStringList.Create();//создаем список в котором //перечислим имена колонок и типы их данных Columns.Add('Name=VARCHAR(20)'); //добавляем колонку Name //с текстовым типом данных длина поля 20 символов Columns.Add('SurName=VARCHAR(20)'); //добавляем колонку 'SurName DB.AddTable('Payments',Columns); //Вызываем функцию добавить таблицу Columns.free;//уничтожаем список, он нам больше не нужен //добавим в созданную таблицу еще одну колонку, другим способом: DB.AddColumn('Payments', 'Summ', 'numeric(15,2)');//добавили колонку Summ end; end; |
Добавить таблицу также можно запросом:
1 2 3 4 5 6 7 8 9 10 11 |
DB := TDataBases.Create(self); DB.ConnectToBase('C:\DBFile.mdb'); DB.ConnectToTable('Table1'); //добавление таблицы запросом DB.QueryText := 'CREATE TABLE Payments (Name VARCHAR(20),SurName VARCHAR(20),Summ numeric(15,2));'; Db.SendCommand; //вставка дополнительной колонки запросом DB.QueryText := 'ALTER TABLE Payments ADD COLUMN AnotherName VARCHAR(20);'; Db.SendCommand; |
Удаление колонки и таблицы происходит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//удаляем колонку из таблицы DB.DeleteColumn('Payments', 'AnotherName'); //или запросом DB.QueryText := ' ALTER TABLE Payments DROP COLUMN AnotherName;'; Db.SendCommand; //удаляем таблицу из базы DB.DeleteTable('Payments'); //или запросом DB.QueryText := ' Drop TABLE Payments;'; Db.SendCommand; |
Структуру таблицы в базу данных мы занесли, теперь необходимо чем нибудь заполнить эту таблицу. Специальных функций для вставки строк нет. Это можно сделать только запросом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//вставляем первую строку DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Иван') + ' , ' + QuotedStr('Иванов') + ' , ' + FloatToStr(10000.50) + ');'; DB.SendCommand; //вставляем вторую строку DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Петр') + ' , ' + QuotedStr('Петров') + ' , ' + FloatToStr(28000.70) + ');'; DB.SendCommand; //вставляем третью строку DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Александр') + ' , ' + QuotedStr('Александров') + ' , ' + FloatToStr(300.98) + ');'; DB.SendCommand; |
Далее мы бы хотели посмотреть, что же у нас получилось. Для этого необходимо выполнить запрос с конструкцией SELECT FROM.
Также необходимо отрисовать колонки в таблице с именем Table1, которую мы поместили на форму. Это делается с помощью процедуры CreateColumnsInTable;
1 2 3 4 5 6 |
//пишем запрос, выбрать все строки и колонки из таблицы Payments DB.QueryText := 'Select * from Payments'; DB.MakeQuery; //для отправки на сервер конструкции select from необходимо //использовать эту команду //после того как запрос выполнен и у нас есть выборка, мы можем дать //команду нарисовать колонки в таблице, которую мы подключили db.CreateColumnsInTable; |
Приведу полный листинг программы которая у меня получилась:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
var DB:TDataBases; Procedure Form1OnCreate(Sender: TObject); var Columns: TStringList; begin DB := TDataBases.Create(self);//создаем экземпляр класса DB.ConnectToBase('C:\DBFile.mdb');//подключаемся к файлу бд DB.ConnectToTable('Table1'); //подключаемся к таблице на форме if not DB.TabExists('Payments') then //проверяем есть ли в файле таблица begin //если ее нет то добавляем ее Columns := TStringList.Create(); Columns.Add('Name=VARCHAR(20)'); Columns.Add('SurName=VARCHAR(20)'); Columns.Add('Summ=numeric(15,2)'); DB.AddTable('Payments',Columns); //вставляем в таблицу строку 1 DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Иван') + ' , ' + QuotedStr('Иванов') + ' , ' + FloatToStr(10000.50) + ');'; DB.SendCommand; //вставляем в таблицу строку 2 DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Петр') + ' , ' + QuotedStr('Петров') + ' , ' + FloatToStr(28000.70) + ');'; DB.SendCommand; //вставляем в таблицу строку 3 DB.QueryText := 'INSERT INTO Payments (Name,SurName,Summ) VALUES (' + QuotedStr('Александр') + ' , ' + QuotedStr('Александров') + ' , ' + FloatToStr(300.98) + ');'; DB.SendCommand; end; //делаем запрос к базе, чтобы показать нашу таблицу на форме DB.QueryText := 'Select * from Payments'; DB.MakeQuery; //даем команду создать колонки в таблице на форме db.CreateColumnsInTable; end; |
После выполнения этого кода мы увидим следующий результат:
Если в коде программы нам захотелось вдруг узнать сумму выплаты которая причитается Иванову Ивану, то мы должны написать следующий код:
1 2 3 4 5 6 |
// пишем запрос с отбором по полю SurName DB.QueryText := 'Select * from Payments where SurName = ''Иванов'''; DB.MakeQuery; //отправляем запрос if DB.First then //позиционируемся на первой строке полученной выборки ShowMessage(FloatToStr(DB.GetFieldValue('Summ'))); //если первая строка есть, то сообщаем значение поля Summ |
После выполнения запроса командой MakeQuery, и когда мы сделали с выборкой все что хотели и она нам больше не нужна можно вызвать метод Close класса, который закроет соединение с базой.
Пожалуй нам осталось рассмотреть еще 1 метод:
Function ClearTable(TableName: string): Boolean; — удалить все строки из талицы с именем TableName.
Для того чтобы сделать аналогичное запросом необходимо написать следующее:
1 2 3 4 5 6 7 |
//удалить все строки из таблицы Payments DB.QueryText := ' DELETE FROM Payments'; DB.SendCommand; //удалить одну строку об Иванове из таблицы DB.QueryText := ' DELETE FROM Payments where SurName = ''Иванов'''; DB.SendCommand; |
Пожалуй на этом я закончу пересказывать вам учебник по SQL. И предлагаю поизучать его самостоятельно.
Другие команды, позволяющие манипулировать данными таблицы можно узнать тут http://www.sql.ru/docs/sql/u_sql/ch15.shtml