Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Базы данных с нуля

Поиск:
Что такое базы данных?

Базы данных существуют следующих видов:

1) Древовидные - простейший пример - Windows Registry, файловая система FAT и XML - здесь информация хранится в древовидной структуре и доступ осуществляется через "путь", т.е. указание всех узлов от корневого до нужного. Например: "c:\My Docs\MyPictures\Me.jpg". Недостатки этого способа хранения данных является очень медленный поиск, если не известен путь и очень плохая устойчивость к повреждениям структуры. Преимущество - возможность хранить в классифицированном виде очень разнородную информацию и очень быстрый поиск при знании ключа. Эти базы данных мы разбирать здесь не будем.

2) Сетевые базы данных - простейший пример - интернет. Т.е. существуют узлы, обособленные друг от друга, содержащие определённую информацию. Каждый узел представляет какое-то количество ссылок на другие узлы, по которым и ведётся поиск. Недостатки - очень сложный и долгий поиск, возможна неполное предоставление информации или невозможность найти нужную информацию. Преимущества - очень легко добавить любую, разнородную информацию, самая высокая стабильность из всех систем. Эти базы данных мы разбирать здесь не будем.

3) Объектные базы данных - новое веяние. Их мы разбирать здесь не будем, но интересующиеся найдут интересной дискуссию о них в нашем разделе по базам данных.

4) Реляционные базы данных - именно с ними мы и будем работать. В дальнейшем если говорится "база данных", то подразумевается "Реляционная база данных". "Реляционный" - Relation - обозначает взаимосвязанный. С этими связями мы будем разбираться потом, а пока можно для простоты считать, что реляционная база данных - это набор двумерных простых таблиц. Недостатки реляционных баз данных - хранение только однородной информации, сложности в добавлении новых структур и взаимоотношений, информация хранящаяся в такой БД должна быть в нужной степени абстрагированна. Преимущества - прежде всего очень высокая скорость поиска - по этому параметру у реляционных баз данных конкурентов нет, высокая стабильность, обилие софта для их поддержки и разработки, удобность для очень широкого круга задач.

Реляционная база данных

Итак, Реляционная база данных упрощённо является набором таблиц. Таблица же есть основной строительный кирпичик базы данных. Расмотрим структуру таблицы. Для начала представте себе таблицу, например в Word...
Что в ней есть?

Во-первых есть строки и колонки (raw and columns). В базах данных, в отличие от Word есть строгие ограничения на их содержимое, да и терминология немного другая:
1) Колонка называется тоже columns, но чаще употребляется понятие "поле" (field). Колонка всегда имеет имя (по которому ее можно найти) и обязана хранить данные только одного какого-либо типа - например целые числа, строки, дату/время и т.п. Создавая таблицу вы обязаны указать какой тип имеет каждое поле, другими словами, вы заранее должны определится, какого сорта данные будут хранится в колонке. Например, вот примерно так может выглядеть структура таблицы для хранения данных об участнике этого форума:

· Ник - строка (25 символов)

· ФИО - строка (250 символов)

· Дата регистрации - Дата/время

· Количество постингов - Целое

· Показывать email - True/False



Обратите внимание что для строк я указал конкретную длину, а для остальных ничего не указывал. Зачем? Ответ прост - каждая строка должна занимать строго одинаковое место (об исключениях потом), и это сделано для быстроты поиска. Действительно , если бы каждая строка имела разную длину, то чтобы найти например 1000 строку, надо было бы перечитать все 999 предыдущих строк, но если известно, что каждая строка занимает например 1Кб, то чтобы прочитать 1000 строку достаточно прочитать 1 Кб с 999Кб... Другая сторона этого - например мне надо сравнить даты в приведенной выше таблице - сделать это просто - я точно знаю что первую дату можно прочитать с 276 байта, и так же точно я знаю точные координаты каждой даты. Именно в этом и лежит одна из сторон высокой скорости работы баз данных (другие способы ускорения работы рассмотрим позже).

2) Строка - в базах данных имеет специфическое название - запись (Record) - к Дельфийскому типу Record этот термин не имеет никакого отношения. Хотя большинство БД дают возможность перейти и прочитать например 10 запись, надо с самого начала попытаться никогда этим не пользоваться. Почему? Да просто потому что БД практически всегда подразумевают совместный доступ нескольких пользователей к одним и тем же данным, и если Вы хотите перейти на 10 запись, а другой пользователь в это время удалит запись номер 5, то вы перейдёте вовсе не на ту запись что ожидалось. А как же быть? У вас есть 2 способа - либо вы находите нужную запись по значению поля - например для нашей таблицы это будет выглядеть примерно так:

"Найти пользователя [Вася] в первой колонке"

В результате вы получите доступ ко всем полям записи для "Васи". Либо вы берёте все записи и перебираете их в цикле пока не найдёте нужный - это гораздо худший способ, так как работает на 2-3 порядка медленнее и имеет другие неприятные последствия (об этом позже), но он возможен и иногда применяется.

Первая программа с базами данных
После небольшого теоретизирования спустимся с небес на землю откроем Дельфи и напишем простейшую программу для баз данных. Напишем, это громко сказано, потому что писать ничего не прийдётся, только компоненты потыкаем.

Открываем новый проект. Открываем форму. Кладём на форму компонент TTable (с закладки "Data Access" или "BDE" - у кого какая версия Дельфей). Оп! Не ожидали - вроде бы и таблица, а компонт не визуальный! Итак компонент TTable - это пока основной компонент для нашей базы - всё обращение к таблице идёт только через него. Теперь давай-те его подсоединим к базе данных.

К Дельфи прилогается учебная база данных, её мы и будем пользовать. Найдите свойство DatabaseName и из выпадающего списка выберите "DBDEMOS" - это и есть учебная база данных. Теперь берём свойство TableName и в выпадающем списке обнаруживаем список имён всех таблиц в базе данных "DBDEMOS", выбираем например "biolife.db" - это таблица так называется (а в данном случае и название файла)

Всё - таблица подсоединена, и с ней даже можно работать, но только в коде. А мы, как особо ленивые, попробуем на сегодня без кода обойтись, а подключить к таблице грид и другие визуальные компоненты.

Но все визуальные компоненты могут подсоединится к TTable только через вспомогательный компонент TDataSource - находящийся на той же закладке. Ставим и его на форму. Находим свойство DataSet у этого компонента и в выпадающем списке указываем на Table1. Теперь визуальные компоенты будут "видеть" инфу в таблице через TDataSource.

Переходим на другую закладку компонентов - "Data Controls" и ставим компоент TDBGrid. В его свойстве DataSource указываем на DataSource1. Что видим? Пока ничего! Таблица то не открыта - кликаем на Table1 и устанавливаем свойство Active в True. Работает!

Можно программу откомпиллировать и поиграться со своим первым приложением для баз данных. Неправда ли очень просто!

Визуальные компоненты для DB

Итак, мы не написав ни строчки кода получили простейшее приложение, работающее с базой данных. С помощью него мы можем просматривать и редактировать содержимое таблицы. Давайте теперь сделаем эту процедуру немного удобнее, на закладке "Data Control" есть компонент TDBNavigator. Положим его на форму и в инспекторе объектов поставим его свойство DataSource указывающим на тот же DataSource1, что и для DBGrid - собственно, теперь оба визуальных контрола(DBGrid и DBNavigator) привязаны к одному и тому же DataSource и через него к одной и той же таблицы. DBNavigator имеет несколько кнопок (вы можете настроить какие именно вы хотите видеть) дающие лёгкий контроль над следующими операциями:
(перечисление в порядке расположения кнопок)
1) Переход на первую запись

2) Переход на предыдущую запись

3) Переход на следующую запись

4) Переход на последнюю запись

5) Добавить запись

6) Удалить запись

7) Редактировать запись

8) Сохранить изменения

9) Отменить изменения

10) Перечитать таблицу




Обратите внимание, что запись (строка) таблицы есть как бы неделимый квант информации - т.е. отменяются действия произведенные для всей записи целиком, добавляется или удаляется тоже строка целиком.

Разберём ещё несколько визуальных компонентов, чтобы покончить с визуализацией данных и перейти собственно к программированию.

На закладке Data Controls есть ещё несколько важных компонентов, давайте поставим их на нашу форму: DBLabel, DBEdit, DBMemo и DBImage. Все их так же как и DBGrid соединим с DataSource1. Однако здесь мы обнаружим что этого недостаточно, эти компоненты работают с отдельной ячейкой в таблице, поэтому мы должны указать ещё поле (столбец) который они будут показывать.
Давайте сделаем следуюшие - для каждого из этих компонентов укажем свойство DataField, например следующим образом:

DBLabel - ассоциируем с полем Category
DBEdit - ассоциируем с полем Common_name
DBMemo - ассоциируем с полем Notes
DBImage - ассоциируем с полем Graphic

Можно откомпилировать программу и немного поиграться с ней. Итак что мы можем здесь увидеть? Что в каждый данный момент времени из всей таблицы у нас есть запись которая активная (текущая) - в DBGrid она показывается треугольничком слева. Именно с этой единственной записью мы и можем оперировать - удалять, добавлять, редактировать, именно её содержимое отображается в DBLabel, DBEdit, DBMemo, DBImage и именно она может быть изменена при помощи этих компонентов. Описанная только что структура позволяет работать только с одной записью в определённый момент времени, если вы переходите на другую запись то все изменения должны быть либо запомнены либо отменены! По умолчанию они запоминаются без всяких запросов, в чём вы можете убедиться меняя значения и переходя на другую запись.

Работа с таблицами в коде

Пока мы рассмотрели самые простейшие и самые не эффективные операции над базами данных, которые нужны лишь в очень ограниченных случаях - их недостаток очевиден - операции роводятся только с одной записью и эти операции только визуальные. Чем это плохо? - это самый медленный способ работы с базами. Он годиться только для работы с данными в ручную, все остальные операции, которые не требуют визуализации не должны работать таким образом.

Итак, начинаем разбирать способы работы с базами данных в коде.
Прежде всего заметим, что работать мы будем только с компонентом Table1. Сразу предупреждаю - КАТЕГОРИЧЕСКИ НЕ СЛЕДУЕТ ПЫТАТЬСЯ ИЗ КОДА МЕНЯТЬ ЗНАЧЕНИЯ В ВИЗУАЛЬНЫХ КОМПОНЕНТАХ, не следует пытаться менять или читать значения из DBGrid, DBEdit и т.д. Эти компоненты существуют только для работы оператора "вручную". Для доступа к данным из кода надо использовать только невизуальные компоненты типа TTable (в дальнейшем мы разберём и другие компоненты для работы с данными - но в любом случае это будут не визуальные компоненты).

Представив себе обычную таблицу, понятно что для доступа к данным надо определить столбец(поле) и строку(запись) в которой эти данные находятся. Давайте разбирать по очереди.

1) Определить поле задача очень простая. Способов здесь 2:
или по имени:

Код
Table1.FieldByName('Category')


или по номеру столбца

Код
Table1.Fields[1]


Оба выражения являются объектом наследованным от типа TField

Я не буду разбирать этот объект подробно, только приведу пример как можно пользоваться этим объектом для доступа к содержимому ячейки таблицы. Содержимое может быть разных типов, поэтому можно использовать следующие методы в зависимости от типа данных:

Код
Table1.FieldByName('Category').AsString
Table1.FieldByName('Category').AsInteger
Table1.FieldByName('Category').AsBoolean
Table1.FieldByName('Category').AsDateTime
Table1.FieldByName('Category').AsFloat


Например, поставте на форму кнопку, и на onClick напишите следующий код:

Код
Showmessage(Table1.FieldByName('Category').AsString);


При нажатии на кнопку вы увидите содержимое столбца 'Category' для текущей записи. Аналогично для обращения по номеру:

Код
Showmessage(Table1.Fields[1].AsString);


Обратите внимание, что на этапе компилляции компиллятор абсолютно не знает о реальном типе данных в поле таблицы. Это выяснится только при попытке выполнить строку. Что будет если типы не совпадают? Если тип можно конвертировать - то ничего страшного, например если у вас поле с целым числом 123, то обращение к полю через AsString выдаст результат - строку '123'. Но если типы не совместимы, то будет сгенерирована ошибка, например такая строка почти наверняка в нашем приложении приведёт к ошибке:

Код
var i:integer;
...
i:=Table1.FieldByName('Category').AsInteger;
showmessage(inttostr(i));


Потому что реальные данные не могут быть приведены к целому типу.

Теперь давайте разбираться как нам добраться до нужной строки, другими словами, до нужной записи. Как я уже говорил мы можем работать только с одной "активной" записью, поэтому задача сводится к установке нужной записи "активной" (К знатокам баз данных - я упорно и намеренно обхожу стороной понятие "курсор" и попытаюсь провести повествование без его упоминания, с целью упрощения понимания материала и не хочу углублятся в материал, без которого можно на первых порах обойтись). Итак, прежде всего Table компонент имеет 4 метода которые помогут нам пройти через все строки
таблицы:

Table1.First - переход на первую запись
Table1.Last - переход на последнюю запись
Table1.Prior - переход на предыдущую запись
Table1.Next - переход на следующую запись

А так же 2 полезных свойства:

Table1.RecordCount - возвращает количество записей (строк) в таблице
Table1.Eof - возвращает TRUE если достигнута последняя запись, в остальных случаях FALSE


Давайте на нашу форму положим компонент Memo (на сей раз обычное, а не dbMemo).

Вот этот простейший код позволит пройти таблицу от начала до конца и считать значения одного поля для всех записей в Memo:

Код
Table1.First;//переход на первую запись
While not Table1.eof do //делать цикл пока таблица не закончится
begin  

Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи  

Table1.Next;//переходим на следующую запись  
end;


Или это же самое можно сделать например так:

Код
Table1.First;
For i=0 to Table1.recordcount-1 do
begin  

 
Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи  

Table1.Next;//переходим на следующую запись  

end;


Второй способ гораздо хуже. Он имеет следующие недостатки:

1) Не для всех баз данных метод Table1.recordcount возвращает правильное значение. Иногда Table1.recordcount устанавливается только после перехода на последнюю запись(это не глюк, это вполне объяснимое поведение, например если у вас есть хорошая табличка размером в несколько гигабайт на другом компьютере, то Table вовсе не скачивает всю эту таблицу локально, а достаёт данные только по мере необходимости). К счастью этот недостаток легко устраним, надо код преобразовать до следующего вида:

Код
Table1.Last;
Table1.First;
For i=0 to Table1.recordcount-1 do
begin  

Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи  

Table1.Next;//переходим на следующую запись  
 
end;


Несмотря на кажущуюся бессмысленность это работает.

2) А вот другой аспект - всегда надо помнить о многопользовательском доступе к таблицам - что случится, если во время прохода по записям другой пользователь добавит или удалит запись?

Доступ к базам данных
Теперь, после работы руками, попробуем разобрать несколько менее призёмлённых вещей. Для начала следует упомянуть что Вы наверное уже прочуствовали что такое таблица. Теперь немного остановимся на базе данных. Базу данных можно очень упрощённо представить как несколько разных таблиц. Они могут быть связаны между собой, а могут и нет. Как физически хранятся таблицы? В трёх видах:

1) Каждая таблица это отдельный файл. Так работают наиболее древние базы данных, например Парадокс (который мы пока используем в примерах), Dbase, FoxPro. Все файлы таблиц лежат в отдельном каталоге на диске. Этот каталог и называется базой данных.
2) Все таблицы хранятся в одном файле – например MS Access – именно этот файл и называется базой данных
3)Таблицы хранятся на специальном сервере – например MS SQL Server, Oracle. В данном случае нас вообще не интересует как сервер хранит эти таблицы – для нас прямой доступ к ним закрыт, мы можем лишь послать запрос на сервер и получить ответ.

Несмотря на значительную разницу в организации, работа с разными базами данных очень сходная (во всяком случае до углубления в дебри). В целом, Вам нет смысла копаться в реальных форматах файлов, нет смысла искать что в файле biolife.db означает 10й байт. Может показаться что всю работу над этим файлом делает компонент TTable в нашем примере. Но это не так! Я наверное удивлю многих если скажу, что компонент TTable реально является только интерфейсом, для лёгкого доступа к данным из Дельфи. Оказывается, что всю работу над таблицей делает специальный драйвер базы данных (или его ещё называют провайдер). Итак упрощённая схема общения с таблицей из программы выглядит примерно следующим образом(для нашего примера):

База Данных <-> Драйвер Базы Данных <-> TTable <-> наш код или др. компоненты

Итак драйвер БД «знает» тонкости и детали строения файла таблицы, или знает конкретные форматы запроса к серверу на «входе», а на выходе имеет некий универсальный «интерфейс» (Я имею ввиду широкое понятие слова «интерфейс», вне контекста с COM) к которому и подключается TTable. Естественно что каждая база данных, и даже каждая версия базы данных имеет свой уникальный формат, свои уникальные особенности, поэтому драйвер для каждой разновидности баз данных тоже уникальный и обычно создаётся производителем баз данных. Интерфейс на «выходе» тоже должен быть стандартизованным – тогда работа с разными базами данных будет значительно облегчена, конечно до истиной переносимости кода далеко (хотя для простейших програм можно легко перенести код для работы с другой базой данных) – сказываются очень большие различия в архитектуре баз данных, которые просто невозможно свести 100% к одинаковому интерфейсу, но в любом случае знакомство с одной базой данных позволяет с лёгкостью разобраться с другой... Как всегда существует несколько стандартов таких «выходных интерфейсов». Наиболее широкораспространены следующие «стандарты» или системы доступа к базам данных:

1)BDE – Borland Database Engine (или по-старому IDAPI). Мы как раз работали в наших примерах именно через эту систему. Эта система является «родной» для Дельфи и отличается весьма высокой производительностью при работе с локальными базами данных. С серверными базами данных её производительность гораздо скромнее. Она же является «родной» для Парадокса, что обусловливает очень высокую производительность и удобство работы связки Delphi-BDE-Paradox (конечно для небольших систем с малым количеством пользователей). BDE имеет в своём составе драйвера практически ко всем более или менее известным базам данных в среде Windows. Позже мы подробнее остановимся на настройке BDE.
2)ODBC – продукт был создан Microsoft как конкурент BDE. На большинстве баз данных он показывает меньшую производительность чем BDE, из Дельфи с ним работать не так удобно, но он так же имеет в своём составе драйвера практически ко всем более или менее известным базам данных в среде Windows. Его настройки можно найти в «Панели Управления» Windows. Есть бесплатная библиотека компонентов для работы с ODBC с исходными кодами, её можно взять с моего сайта: http://www.delphist.com. Для программиста на Дельфи представляет очень ограниченный интерес – большинство возможностей реализовано в BDE, причём BDE со многими базами работает быстрее и Дельфи имеет собственные компоненты для BDE.
3)DAO – это очень старая система для доступа к MS Access и MS Excel (она так же поддерживает ещё несколько баз данных), отличается высокой производительностью и богатым набором функций для работы именно с MS Access и MS Excel. Вообще не поддерживает работу с серверными базами данных. DAO можно использовать для работы с MS Access и MS Excel когда критична производительность приложений и/или требуется всё богатство возможностей доступа к MS Access и MS Excel. Есть бесплатная библиотека компонентов для работы с DAO с исходными кодами, её можно взять с моего сайта: http://www.delphist.com.
4)ADO (ActiveX Data Object) – новая система от MS ориентированная прежде всего на работу с серверными базами данных. Довольно удобна в использовании, Дельфи начиная с 4й версии в модификации Enterprise/Professional имеет линейку собственных компонентов для работы через ADO. Позднее мы рассмотрим работу с ADO компонентами.

Кроме перечисленных есть ещё по крайней мере десяток других широкоизвестных систем доступа к базам данных, и огромное количество "отдельностоящих" драйверов для конкретной базы данных.

Приёмы работы с BDE
Те примеры с которыми мы работали использовали именно BDE. Давайте рассмотрим вопросы, напрямую связанные с BDE:

1) Где физически хранится моя база данных
2) Как создать базу данных
3) Как создать таблицу

Итак, где физически хранится моя база данных и собственно куда мы обращались в наших примерах? Если вы помните, в наших примерах мы свойство DatabaseName для Table установили в "DBDemos". Что же это такое "DBDemos"? - это название базы данных, или в терминологии BDE - Alias (перевод на русский язык "Псевдоним"). Alias - это некая "структура" BDE, которая указывает на физическое расположение файлов базы данных, а так же хранит некоторые свойства (параметры) доступа к базе данных. Эти параметры можно посмотреть, настроить, а также добавить или удалить Alias используя программу "BDE Administrator" которую можно найти в Control Panel (панель управления Windows). Запустите BDE Administrator и найдите в левом дереве DBDemos. Теперь на правой части можно увидеть его свойства, например там вы найдёте путь к базе данных. С помощью BDE можно удалить Alias или добавить новый

Создание базы данных
Итак, Как создать базу данных?

Пока мы рассматриваем Paradox осмелюсь заметить, что база данных ничто иное как папка (каталог) на диске. Надеюсь что читателю не составит труда создать пустой каталог, например "c:\MyDBExample". Теперь создадим Alias на этот каталог:

1) Открываем BDE Administrator, нажимаем menu->Object->New (или Ctrl-N)
2) В выскочившем окне выбираем Standard, жмём Ok
3) На левой панеле переименовываем название Alias во что-нибудь, например "MyDB"
4) На правой панеле, в разделе PATH указываем c:\MyDBExample
5) Сохраняем изменения

Закрываем BDE Administrator. Загружаем Дельфи с нашим примером, убеждаемся, что в свойстве DatabaseName у таблицы появился среди вариантов выбора и наш Alias - "MyDB".

А как создать базу данных программно? Забегаю вперёд, новички могут со спокойной совестью эту информацию пропустить.

С созданием базы данных програмно большие проблемы! Задача состоит из 2х этапов:

1) Создание самой базы данных
2) Создание Alias

Второй вопрос весьма прост - используются методы системного объекта Session:
Код
session.AddAlias
Session.SaveConfigFile


Ответ же на первый не однозначен и вызвано это тем, что это целиком зависит от базы данных. Так как Dbase и Paradox базы данных это просто каталоги, то тут проблем нет, создаём каталог (ForceDirectories например) и дело с концом, для MS Access и MS Excel уже прийдётся использовать DAO низкоуровневые функции, серверные базы данных обычно имеют системные Stored Procedures для создания базы данных.

Создание таблицы
Как создать таблицу?

Вариантов несколько:

1) Сделать это с помошью менеджера соответствующей базы данных, например таблицу для Paradox создать в Paradox'e
2) С помощью Database Desktop - утилита , постовляемая с BDE и большинством борландовских продуктов. Я не думаю что вы встретите проблемы при создании таблицы - там всё очень просто.
3) Из программы.
Здесь 2 варианта, вариант первый, использовать метод CreateTable у таблицы, вот пример из справки по Дельфи как Борланд предлагает это делать:

Код
with Table1 do begin
 Active := False;  
 DatabaseName := 'DBDEMOS';
 TableType := ttParadox;
 TableName := 'CustInfo';
 { Don't overwrite an existing table }
 if not Table1.Exists then begin
   { The Table component must not be active }
   { First, describe the type of table and give }
   { it a name }
   { Next, describe the fields in the table }
   with FieldDefs do begin
     Clear;
     with AddFieldDef do begin
       Name := 'Field1';
       DataType := ftInteger;
       Required := True;
     end;
     with AddFieldDef do begin

       Name := 'Field2';
       DataType := ftString;
       Size := 30;
     end;
   end;
   { Next, describe any indexes }
   with IndexDefs do begin
     Clear;
     { The 1st index has no name because it is
     { a Paradox primary key }
     with AddIndexDef do begin
       Name := '';
       Fields := 'Field1';
       Options := [ixPrimary];
     end;
     with AddIndexDef do begin
       Name := 'Fld2Indx';
       Fields := 'Field2';
       Options := [ixCaseInsensitive];
     end;
   end;
   { Call the CreateTable method to create the table }
   CreateTable;
 end;
end;


Есть другой метод, который нравится мне гораздо больше, он проще в реализации и работает стабильнее - выполнить Query типа "Create Table". Этот способ я разберу позже, когда мы будем рассматривать работу с запросами.

Изменение данных в таблице
Теперь последний штрих о работе с таблицами. Мы разобрали способы обратиться к нужному столбцу и нужной записи, их поиск и чтение значений. А как записать новое значение? Для этого есть методы Edit, Append, Insert, Post и Cancel.

1) Надо изменить текущую запись.
Код
Table1.edit; //переводим таблицу в режим редактирования  
Table1.fieldbyname('Category').asString:='New value';//изменяем поле  
Table1.post;//сохраняем изменения



2) Надо добавить новую запись.
Table1.append; //переводим таблицу в режим добавления новой записи
Table1.fieldbyname('Category').asString:='New value';//присваиваем значение полей
Table1.post;//сохраняем изменения

Итого, как видим изменения данных производятся точно так же как и чтение, но перед изменением КАЖДОЙ записи таблица должна быть переведена в режим редактирования, а после изменения КАЖДОЙ записи изменения должны быть сохранены.

В режим редактирования таблицу переводят следующие методы:
Edit - редактирование текущей записи
Append - добавление записи в конец таблицы
Insert - вставка записи перед текущей

Для выхода из режима редактирования служат методы:
Post - запомнить изменения и выйти из режима редактирования
Cancel - отменить сделанные изменения и выйти из режима редактирования

Понятие о запросе (Query)
Итак, это пожалуй почти всё, что мы можем "выжать" из компонента TTable. Почуствовали мощь и удобство работы с базами данных? - Ой, вряд ли! Скорее всего ощущение заумности, убогости и неудобства в сочетании с крайней медлительностью операций... Действительно доступ к базе данных через TTable является самым прямым и самым неудобным, какие же основные недостатки? Наверное уже многие задались вопросами:

1) А если мне надо 1000 записей изменить, так мне надо в цикле крутить приведенный код? Так это ж как долго!

2) Ну хорошо, у меня есть табличка на сотню тысяч записей, и мне нужно из неё выбрать только, например, 1000 записей касательно "Иванова", так мне прийдётся всю таблицу в цикле крутить пока не найду то что мне нужно?

Все эти проблемы решены, и решены великолепно - просто, очень эффективно и с минимальными затратами.

Рассмотрим в кратце общий алгоритм доступа к информации который был рассмотрен:

1.1) Передать данные из таблицы в программу
1.2) Программа сама занимается поиском данных

А что если изменить схему:
2.1) Отдать команду драйверу на поиск нужной информации
3.2) Драйвер найдёт инфу
2.3) Найденная информация будет возвращена программе.


На первый взгляд разница только в том что работу, которую делает программный код в первом случае, мы пробуем свалить на драйвера базы данных. Ну и зачем? Оказывается есть зачем! В первой схеме - есть несколько моментов на которые я бы хотел обратить внимание:

1) В любом случае манипулирование базой производится драйвером, следовательно код драйвера в любом случае работает. Драйвер написан под конкретную базу данных, и "знает" каким образом манипулировать с базой самым быстрым способом, а програмный код неизбежно подвергается "транслированию", многочисленным преобразованиям данных для обеспечения совместимости.
2) А если база данных находится на другом компьютере? Тогда программа вынуждена "вытащить" все данные на локальный компьютер перед манипулированием данными, что есть совсем не быстрая операция. Кстати пока мы тащим гигабайтную таблицу к себе, ваш сосед Вася уже успел там что-то поменять, и что теперь? Тащим заново, или посылаем Васю подальше, и не даём ему работать с базой пока сами не закончим?

А во втором способе всё будет куда лучше! Программа попросит данные и получет только те данные которые запрошены, а не всю таблицу, никаких трансляций данных - мы транслируем только те данные, которые уже отобраны, а не всё подряд, всю работу мы переложили на плечи драйвера, который был написан очень оптимально, который точно знает как работать именно с этой версией базы данных, а не со всеми подряд. А Вася нас тоже пока не интересует, драйвер сам разберётся как с ним поступать - нас это не касается (пока по крайней мере).

И как же это реализовано? Это реализовано с помощью языка запросов: SQL. Подробнее этот язык рассмотивается в разделе Базы данных, мы же не заостряя внимание на самих запросах, рассмотрим простейшие случаи как этот язык можно применить внутри программы на Дельфи и какие выгоды можем мы получить используя запросы.

Итак, из нашего тестового проекта удаляем компонент Table1. Вместо него ставим компонент TQuery. Устанавливаем Alias (DatabaseName) и связываем его с DataSource таким же образом как и таблицу.

Пока вы найдёте 2 радикальных отличия от TTable:
1) Нет свойства TableName
2) Открытие (Active:=true) квери приводит к ошибке

Query должна содержать запрос. Для этого есть свойство SQL, являющееся самым обыкновенным TStringList. Откроем это свойство и напишем примерно следующее:


Код
Select * from biolife


Теперь можно попытаться открыть квери (установить Active в True) и вы получите точно тоже что и в первом примере - грид заполненный данными из таблицы Biolife.db. Мало того, всё что мы проделывали с таблицей - позиционирование строки, чтение и запись полей и т.п. вы можете с успехом сделать и с Query - причём синтаксис тот же самый! Пока мы только сделали замену компоненту TTable и не более того.

Я здесь не буду подробно останавливаться на синтаксисе SQL запроса, материал по этой теме вы найдёте здесь:

http://forum.vingrad.ru/index.php?act=ST&f=12&t=5638

Однако простейшие приёмы работы я покажу. В нескольких дальнейших примерах мы будем менять свойство "SQL". Перед каждым изменением этого свойства Вы должны закрывать квери (в дизайне устанавливать Active в False). В run-time изменения SQL должны выглядеть примерно так:

Код
Query1.active:=false;  
Query1.sql.text:='Select * from biolife';  
Query1.active:=true;


Запросы на выбор данных
Теперь покажу на примере как можно использовать квери для наиболее простых, но очень частых и нужных операций:

1) Выбор только тех строк (записей) которые отвечают условию (например тех где в поле category записано 'Snapper')

Код
SELECT * FROM biolife  
where category='Snapper'


2) Выбор только нужных столбцов (например нам нужны только столбцы Category и common_name )

Код
SELECT Category, common_name FROM biolife


3) Выбор записей отсортированных в определённом порядке (например в алфавитном порядке поля Category)

Код
SELECT * FROM biolife  
Order by Category


4) Запрос может комбинировать в себе всё перечисленное

Код
SELECT Category, common_name FROM biolife  
where category='Snapper'  
Order by common_name


Попробуйте задать каждый из этих запросов и посмотреть как программа будет реагировать на него. На самом деле запросы предоставляют гораздо большии возможности - например суммарные и статистические функции (вычислить сумму всех значений поля), вычисляемые поля (например добавить столбец который отражает не реальное поле в таблице, а сумму 2х других полей), объединение нескольких таблиц в одном запросе (2 таблицы с похожей структурой представляются как одна таблица), запросы на несколько таблиц (например вам надо выбрать всех из одной таблицы которые не встречаются в другой таблице, или для Иванова взять его номер телефона из одной таблицы, а его заказы из другой и т.п.). Всё это вы найдёте здесь: http://forum.vingrad.ru/index.php?act=ST&f=12&t=5638 , а в этой статье я только показываю как с этим можно работать из Дельфи

Запросы на изменение данных

А как менять значения в базе данных? Тоже при помощи квери это делать проще и, что важнее, значительно быстрее. Например, меняем в поле Category все "Cod" на "Kod". В квере пишем текст:

Код
Update biolife
Set Category='Kod'
Where Category='Cod'


Ставим на форму кнопку, в обработчике нажания (onClick) пишем код:

Код
Query1.ExecSQL;


Важные примечания:
1) Обратите внимание, что в данном случае мы не открываем квери делая Active:=true и не используем эквивалентный метод Open, а используем метод ExecSQL. Если открытие квери с оператором Select приводит к возвращению данных в программу (так называемый курсор данных), то все остальные типы кверей никаких данных в программу не возвращают - они выполняют операцию над базой, но не возвращают курсор. Такую кверю НЕЛЬЗЯ соединить с визуальными компонентами, её открытие хоть и будет выполнять операцию, будет приводить к исключительной ситуации.

2) Перед изменением текста квери, хоть в дизайне, хоть в run-time кверя должна быть закрыта.

Аналогичным способом можно пользоваться другими операторами SQL:

Delete - для удаления нескольких/всех строк
Insert - для вставки одной или нескольких строк
Create Table - для создания таблицы
Alter Table - для изменения структуры таблицы
Drop Table - для удаления таблицы
и другими. Смотрите руководства по SQL по использованию этих операторов.
Автор: Vit
Сайт: http://chicago.lastplanet.com






Просмотров: 39969

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную