Delphi 3 и создание приложений баз данных

         

Понятие баз данных. Степень детализации информации в базе данных


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

Обычно БД создается для хранения и доступа к данным, содержащим сведения о некоторой предметной области, то есть некоторой области человеческой деятельности или области реального мира. Всякая БД должна представлять собой систему данных о предметной области. БД, относящиеся к одной и той же предметной области, в различных случаях содержат более или менее детализированную информацию о ней. Степень детализации определяется рядом факторов, прежде всего целью использования информации из базы данных и сложностью производственных (деловых) процессов, существующих в пределах предметной области в конкретных условиях.

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

Организация А

характеризуется невысоким ассортиментом хранимых и отпускаемых товаров. Ассортимент отличается стабильностью. Состав реальных покупателей товаров исчисляется несколькими лицами (только юридическими). Предоплаты за еще не отпущенный товар не допускаются, отпуск товара в кредит не практикуется, система скидок отсутствует. Оплата производится в рублях. Отпуск товаров осуществляется с одного склада. Потребности в автоматизации учета отпуска товаров определяются двумя целями:

• быстрой выдачей информации о текущих остатках товара на складе;

• ежемесячной выдачей отчета об общих суммарных отпусках товара.

Организация

Охарактеризуется множеством территориально распределенных складов, в том числе в различных государствах ближнего зарубежья. Ассортимент отпускаемых товаров высок и быстроизменчив в силу изменчивости спроса. Состав покупателей крайне разнообразен, в число покупателей входят как физические, так и юридические лица. Практикуется система скидок постоянным покупателям и покупателям, приобретающим товар свыше определенного количества и (или) суммы. Развита система предоплат, отпуска товаров в кредит. Оплата производится в местной валюте по текущему курсу доллара, реже - рубля. Потребности в автоматизации учета отпуска товаров определяются широким диапазоном целей:

быстрым получением информации о текущих остатках товара, в том числе на конкретном складе;

по регионам;

по всей организации;

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

по конкретному региону, где расположены склады; по конкретному складу; по конкретному покупателю - отдельно для физических и юридических лиц; по группам покупателей, объединенным по одному признаку - например, территориальному; зачетом предоплат и задолженностей отдельных покупателей;

автоматическим переводом покупателей в льготные категории, имеющие право на тот или иной вид скидки;

• прогнозированием с определенным уровнем вероятности будущего спроса (по покупателю, товару, региону) и т.д. Ввиду различия целей внедрения БД и содержания деловых процессов в Организациях А и Б, созданные в этих организациях базы данных будут существенно отличаться друг от друга - прежде всего детализацией хранимой информации и, следовательно, структурой данных. Если для организации А в БД достаточно хранить сведения о приходе и расходе товаров и о ценах на них, то в БД организации Б необходимо хранить десятки таблиц и в процессе работы тратить дополнительные усилия (реализуемые как вручную, так и автоматически) для того, чтобы поддерживать их в согласованном состоянии.





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


Реляционные БД представляют связанную между собой совокупность таблиц баз данных (ТБД). Связь между таблицами может находить свое отражение в структуре данных, а может только подразумеваться, то есть присутствовать на неформализованном уровне.

Каждая таблица БД представляется как совокупность строк и столбцов, где строки соответствуют экземпляру объекта, конкретному событию или явлению, а столбцы - атрибутам (признакам, характеристикам, параметрам) объекта, События, явления.

На рис. 1.1. приведен пример таблицы БД, в которой содержатся сведения об отпуске товара со склада. Столбцы представляют собой такие параметры, как дата отпуска товара, наименование отпущенного товара, наименование покупателя, количество единиц отпущенного товара. Каждая строка содержит введения о конкретном событии отпуска товара покупателю. в терминологии теории реляционных БД таблицам соответствуют отношения, столбцам - атрибуты, строкам - кортежи.

При практической разработке БД таблицы так и зовутся таблицами, строки -записями, столбцы - полями или столбцами ТБД.

Дата

Товар

Покупатель

Отпущено, ед.

10.02.97

Сахар

Геракл, ТОО

100

10.02.97

Сахар

Геракл, ТОО

100

12.02.97

Сахар

Пищеторг, ЗАО

2000

12.02.97

Макароны

Пищеторг, ЗАО

300

14.02.97

Сахар

Геракл, ТОО

200

15.02.97

Дрожжи

База № 28

100

Рис 1 1 Таблица базы данных "Отпуск товаров со склада "

Предшественниками реляционных БД были иерархические и сетевые базы данных. В иерархических БД информация хранилась в виде иерархий. На рис. 1.2 приведен пример такой иерархии; из ее рассмотрения становится ясно, для того, чтобы получить элемент данных А 12, нужно сначала отыскать в БД узел А, спуститься к узлу А1 и затем - к узлу А 12.

Сетевая БД характерна внутренними ссылками между структурами данных. Если от элемента В имеется ссылка на элемент А, возможен выбор элемента данных А (рис. 1.3).

Реляционные БД в 70-х годах практически вытеснили БД других видов. В качестве основной причины этого называют сложность представления данных в иерархической и сетевой моделях и необходимость определения связей между данными на этапе проектирования БД, в то время как в реляционных БД связи между таблицами могут устанавливаться непосредственно в момент выполнения запросов. Кроме того, разработчикам и пользователям значительно проще отображать сущности предметной области в табличных структурах данных.

Однако иерархический и сетевой подходы продолжают жить, они находят свое воплощение в отдельных специализированных БД и являются

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

Реляционные БД имеют мощный теоретический фундамент, основанный на математической теории отношений. Он был разработан доктором Эдгаром Коддом. Для построения запросов к реляционным БД был также разработан язык SQL (Structured Query Language, язык структуризированных запросов). Он приобрел характер промышленного стандарта в реляционных системах управления базами данных (СУБД). Поэтому, переходя с одной реляционной базы на другую, пользователь и разработчик имеют дело с одним и тем же языком. Другим важным плюсом SQL является то, что этот язык ориентирован на высокоуровневые операции с данными. Выдавая запрос, можно не беспокоиться о низкоуровневых проблемах доступа к данным, специфичных для каждой БД, поскольку интерпретация запросов в команды низкого уровня лежит в ведении конкретной СУБД.

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

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



Понятие первичного ключа


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

На рис. 1.4 показана таблица "Сотрудники". В качестве первичного ключа не могут использоваться поля:

• ФИО - поскольку практически известно, что даже в одном отделе могут работать однофамильцы с одинаковыми инициалами или даже полные тезки;

• должность - поскольку хотя для данного примера названия должностей и уникальны, в любом отделе наверняка найдутся сотрудники, занимающие одну и ту же должность;

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

№ пропуска ФИО

Должность

Отдел

Год рожд.

111222

Иванов И.И.

нач. отдела

122

1940

333444

Петров П.П.

диспетчер

122

1942

234567

Сидоров С.С.

наладчик

118

1940

101010

Петраков А.И.

кладовщик

118

1967

202020

Мамукин М.М.

инженер

196

1966

Рис. 1.4. Таблица "Сотрудники"

В качестве первичного ключа может выступать номер пропуска, но при этом нужно сделать оговорку. Если номер пропуска недавно уволившегося сотрудника не может быть назначен сотруднику, впоследствии принятому на работу (т.е. является уникальным во времени), нет никаких ограничений на использование этого поля в качестве первичного ключа. Если же номер пропуска уволившегося сотрудника может быть назначен вновь поступившему сотруднику, следует изучить вопрос - удаляется ли информация об уволившемся сотруднике из базы данных? Если да, то поле может быть первичным ключом; если нет - не может быть первичным ключом, поскольку в базе данных могут присутствовать два сотрудника с одинаковым номером пропуска. В этом случае следует добавить в таблицу семантически незначащее поле (то есть не имеющего иного смысла, кроме обеспечения уникальности записи), например числовое поле NN (рис. 1.5.).

№ продукта

ФИО

Должность

Отдел

Год рожд.

111222

Иванов И.И.

нач. отдела

122

1940

2

333444

Петров П.П.

диспетчер

122

1942

i4

234567

Сидоров С.С.

наладчик

118

1940

>2

101010

Петраков А.И.

кладовщик

118

1967

21

202020

Мамукин М.М.

инженер

196

1966

Рис. 1.5. Таблица "Сотрудники" после введения уникального поля

Уникальность подобного поля обычно отслеживается или программно, или автоматически. В первом случае при добавлении нового сотрудника приложение, работающее с базой данных, отыскивает максимальный номер сотрудника, увеличивает на 1 и назначает вновь добавляемой записи. Во втором случае первичный ключ реализуется через автоинкрементное поле. Для него сказанные действия выполняются автоматически системой управления базой данных. Существуют и иные способы обеспечения уникальности значений ключевого числового поля, они зависят от особенностей конкретной СУБД.

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

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

Приведем другие примеры первичных ключей:

• номер и серия паспорта;

• номер двигателя;

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

• название факультета, кафедры, года приема - для именования учебных групп в вузах;

• номер лицевого счета в бухгалтерском балансе;

• дата - если событие может случиться в течение даты только единожды, например, поставка продуктов в заводскую столовую;

• дата и время отказа сетевого оборудования, а при наличии нескольких потенциально сбойных узлов - адрес (номер) узла (если сбой узла характеризуется несколькими типами ошибок - еще и номер ошибки);

• почтовый адрес организации - с указанием номеров комнат, в случае, если в одном здании располагается несколько организаций (например, офисное здание);

• банковские реквизиты;

• регистрационный номер банка, организации;

• дата, номер страхового полиса, специализация и (или) фамилия и инициалы врача-специалиста - при обращении в поликлинику и т.д.

Замечание.

Может показаться, что банковские реквизиты не могут однозначно характеризовать организацию, поскольку одна организация может иметь несколько счетов в различных банках. Но реквизиты конкретного счета являются уникальными и, следовательно, могут однозначно характеризовать организацию; наименование же организации не может однозначно характеризовать реквизиты ее банковских счетов, которых может быть несколько. На практике, реквизиты счета вряд ли будут использованы в качестве первичного ключа, поскольку эти реквизиты громоздки; тем не менее, с теоретической точки зрения, такое возможно.

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



Отношение "один-ко-многим"


Отношение "один-ко-многим" имеет место, когда одной записи родительской таблицы может соответствовать несколько записей в дочерней таблице.

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

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

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

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

Связь "один-ко-многим" является самой распространенной для реляционных баз данных. Как можно заметить, она позволяет моделировать иерархии данных.

В широко распространенной нотации структуры баз данных IDEFIX отношение "один-ко-многим" изображается путем соединения таблиц линией, которая на стороне дочерней таблицы оканчивается кружком или иным символом. Поля, входящие в первичный ключ для данной ТБД, всегда расположены вверху и отчеркнуты от прочих полей линией (рис. 1.7).



Отношение "один-к-одному"


Отношение "один-к-одному" имеет место, когда одной записи в родительской таблице соответствует одна запись в дочерней таблице (рис. 1.8.).

Данное отношение встречается много реже, чем отношение "один-ко-многим". Его используют, если не хотят, чтобы таблица БД "распухала" от второстепенной информации. Использование связи "один-к-одному" приводит к тому, что для чтения связанной информации в нескольких таблицах приходится производить несколько операций чтения вместо одной, когда данные хранятся в одной таблице. Кроме того, базы данных, в состав которых входят таблицы со связью "один-к-одному", не могут считаться до конца нормализованными (о нормализации см. ниже).

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



Отношение "многие-ко-многим"


Отношение "многие-ко-многим" имеет место, когда:

а) записи в родительской таблице может соответствовать больше одной записи в дочерней таблице;

б) записи в дочерней таблице может соответствовать больше одной записи в родительской таблице.

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

Таблица "Учебные группы и Таблица "Преподаватели" дисциплины"

Группа

Предмет

№ преподавателя

№ преподавателя

ФИО преподавателя

Кафедра

ПС-1

Программирование

10

->

10

Красноов Ю.Б.

ТИ-1

ТИ-1

Программирование

12

 

12

Володин В.Н.

ТИ-1

ПС-1

Теория систем

10 62 Булгаков В.М. РИО РТ-2 Философия 62 78 Гноенский Л.С. ТИ-1 ПС-1 Социология 62 85 Подушкин М.А. ЭИ-1 ... ... ... ... ... ...

Рис 1.9 Связь "многие-ко-многим"

Многие СУБД не поддерживают связи "многие-ко-многим" на уровне индексов и ссылочной целостности (см. следующий подраздел), хотя и позволяют реализовывать ее в таблицах неявным образом. Аналогично, мнногие CASE-средства (программы для разработки структуры базы данных в виде диаграмм и генерации на их основе физической базы данных) также нe позволяют определять эту связь между таблицами проектируемой базы даннь1Х. Считается, что всякая связь "многие-ко-многим" может быть заменена на одну или более связь "один-ко-многим". Хотя это так, по мнению автора, целесообразность применения такой связи должна рассматриваться прежде всего в контексте разрабатываемой базы данных и приложения для работы с ней, и там, где это удобно, такая связь должна реализовываться.



Связь между записями одной таблицы


Между записями одной таблицы также может существовать связь, то есть одни записи могут ссылаться на другие.

Рассмотрим пример. Пусть необходимо в реляционной БД хранить древовидную структуру произвольного уровня, например, структуру организации (рис. 1.10.) В этом случае минимально достаточно таблицы реляционной БД (рис. 1.11), в которой каждому подразделению организации соответствует одна запись. Эта запись ссылается на запись, соответствующую подразделению более высокого уровня, в которое входит данное подразделение. И только в записи о подразделении самого высокого уровня нет подобной ссылки.

Нужно заметить, что автоматическое обеспечение связен записей внутри одной таблицы реляционными СУБД не поддерживается и эти связи нужно реализовывать программно. Несложно заметить, что удаление записи, на которую имеются ссылки (у нас это записи со значением поля "№ подразделения", кроме 4,5,6,8,9,11), должно блокироваться, поскольку в противном случае в таблице будут иметь место ссылки на несуществующие номера подразделений. Также нельзя изменять номера подразделений, на которые имеются ссылки - это разрушит достоверность данных. Такие действия необходимо реализовывать программно. Рассмотренный пример является частным случаем более общей проблемы - обеспечение ссылочной целостности между таблицами базы данных. Речь об этой проблеме пойдет вследующем разделе.



Реляционные отношения (связи) между таблицами базы данных


Между двумя или более таблицами базы данных могут существовать отношения подчиненности. Отношения подчиненности определяют, что для каждой записи главной таблицы (master, называемой еще родительской) может существовать одна или несколько записей в подчиненной таблице (detail, называемой еще дочерней).

Существует три разновидности связей между таблицами базы данных: "один-ко-многим", "один-к-одному", "многие-ко-многим".



Ссылочная целостность и каскадные воздействия


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

Таблица "Товары" Таблица "Отпуск товаров"

Товар

Ед.изм.

Цена ед.

Товар

Дата

Кол-во, ед.

Сахар

кг

5000

-|->

Сахар

10.01.97

100

Макароны

кг

7000

|->

Сахар

12.01.97

200

Куры

кг

10000

|->

Сахар

14.01.97

50

Фанта

бут. 1 л

6000

 

Макароны

10.01.97

1000

 

 

 

 

Макароны

11.01.97

500

 

 

 

 

Фанта

10.01.97

2000

 

 

 

 

Фанта

12.01.97

3000

Рис. 1.12. Связанные таблицы базы данных

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

• изменение значения поля связи в записи родительской таблицы без изменения значений полей связи в соответствующих записях дочерней таблицы;

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

Разберем первый случай. На рис. 1.13 показано изменение значения поля "Товар" с "Сахар" на "Рафинад" в таблице "Товары". В таблице "Отпуск товаров" значение поля связи "Сахар" осталось прежним. В результате:

в дочерней таблице "Отпуск товаров" для товара "Рафинад" (таблица "Товары") нет сведений о его отпуске со склада;

• некоторые записи таблицы "Отпуск товаров" содержат сведения об отпуске товара ("Сахар"), о котором нет информации в таблице "Товары".

Товар Ед.изм. Цена eд Товар Дата Кол-во, ед.
Рафинад кг 5000 --- -|-> Сахар 10.01.97 100
Макароны кг 7000 |-> Сахар 12.01.97 200
Куры кг 10000 |-> Сахар 14.01.97 50
Фанта бут.1 л 6000 Макароны 10.01.97 1000
Макароны 11.01.97 500
Фанта 10.01.97 2000
Фанта 12.01.97 3000

Таблица "Товары" Таблица "Отпуск товаров"

Рис. 1.13. Нарушение целостности базы данных - записи с товаром "Сахар" (таблица "Отпуск товаров") не имеют родительской записи

Разберем второй случай. Пусть в одной из записей таблицы "Отпуск товаров" значение поля связи "Сахар" изменилось на "Рафинад" (рис. 1.14). В результате:

• в дочерней таблице "Отпуск товаров" недостоверны сведения об отпуске со склада товара "Сахар" (таблица "Товары");

• одна из записей таблицы "Отпуск товаров" содержит данные об отпуске товара ("Рафинад"), сведения о котором (такие, как единица измерения и цена за единицу) отсутствуют в таблице "Товары". И в первом, и втором случаях мы наблюдаем нарушение целостности базы данных, поскольку информация в ней становится недостоверной. Следовательно, нужно блокировать действия, которые нарушают целостность связей между таблицами, которую называют ссылочной целостностью. Когда говорят о ссылочной целостности, имеют в виду совокупность связей между отдельными таблицами во всей БД. Нарушение хотя бы одной такой связи делает информацию в БД недостоверной.

Таблица "Товары" Таблица "Отпуск товаров"

Товар ед.изм.

Цена ед.

 

Товар

Дата

Кол-во,ед.

Сахар

кг

5000 ---

-|->

Рафинад

10.01.97

100

Макароны

кг

7000

|->

Сахар

12.01.97

200

Куры

кг

10000

|->

Сахар

14.01.97

50

Фанта

бут.1 л

6000

 

Макароны

10.01.97

1000

 

 

 

 

Макароны

11.01.97

500

 

 

 

 

Фанта

10.01.97

2000

 

 

 

 

Фанта

12.01.97

3000

Рис. 1.14. Нарушение целостности базы данных - запись с товаром "Рафинад" (таблица "Отпуск товаров ") не имеет родительской записи

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

• необходимо запретить изменение поля связи в записи дочерней таблицы без синхронного изменения полей связи в родительской и дочерней таблицах; обычно инициатива изменения поля связи реализуется в записи родительской таблицы;

• при изменении поля связи в записи родительской таблице, следует синхронно изменить значения полей связи в соответствующих записях дочерней таблицы;

• при удалении записи в родительской таблице, следует удалить соответствующие записи в дочерней таблице.

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

Замечание 1. Существует другая разновидность каскадного удаления: при удалении родительской записи в записях дочерних таблиц значения полей связи обнуляются. Эта разновидность применяется редко.

Замечание

2. Обычно занесение записей в дочернюю таблицу осуществляется так: выбирается значение родительской записи (например, из выпадающего списка), значение поля связи фиксируется и затем автоматически заносится в поля связи дочерних записей. Метод, когда пользователь вручную заносит значения полей связи в дочерние записи, непопулярен: пользователь может внести одинаковое по смыслу, но разное по написанию значение ("Сахар", "сахар"). Много реже практикуется способ ввода дочерних записей без указания значения поля связи. Затем записи родительской и дочерних таблиц "связываются".

Каскадные изменения могут блокироваться: или одновременно изменения и удаления, или изменения или удаления по отдельности. Необходимость разрешения или запрещения каскадных изменений обычно реализуется в СУБД при определении связей между таблицами. Собственно, таким образом и происходит создание ссылочной целостности. Обычно в СУБД для реализации ссылочной целостности в дочерней таблице создают внешний ключ (см. ниже), ссылающийся на родительскую таблицу, и указывают вид каскадных

воздействий. В последующем СУБД сама при необходимости реализует каскадные воздействия данного вида для указанных таблиц.



Понятие внешнего ключа


Для обеспечения ссылочной целостности в дочерней таблице создается внешний ключ. Во внешний ключ входят поля связи дочерней таблицы. Для связей типа "один-ко-многим" внешний ключ по составу полей должен совпадать с первичным ключом родительской таблицы или - реже - с частью первичного ключа (в этом случае следует признать, что нормализация таблиц БД произведена не полностью). По определениям первичного и вторичного ключей СУБД автоматически строит индексы (см. ниже). Индекс, соответствующий вторичному ключу, используется для реализации связи родительской и дочерних таблиц. Механизм индексов основан на понятии методов доступа, поэтому рассмотрим их подробнее.



Индексы и методы доступа


Порядковый № записи

Дата прихода товара

Наименование товара

Количество,

1

10.01.1997

Сахар

10

2

12.01.1997

Картофель

50

3

12.01.1997

Свекла

20

4

14.01.1997

Сахар

50

5

14.01.1997

Свекла

10

6

16.01.1997

Сливы

4

Рис. 1.15. Физическая структура таблицы

Индексы представляют собой механизмы быстрого доступа к данным в таблицах БД.

Сущность индексов состоит в том, что они хранят значения индексных полей (т.е. полей, по которым построен индекс) и указатель на запись в таблице. Например, если имеется таблица (рис. 1.15.), то с логической точки зрения индексы выглядят так (рис. 1.16):

По дате прихода товара

По наименованию товара

По количеству

Дата прихода

№ записи

Товар

№ записи

Количество.

№ записи

10.01.1997

1

Картофель

2

4

6

12.01.1997

2

Сахар

1

10

1

12.01.1997

3

Сахар

3

10

5

14.01.1997

4

Свекла

3

20

3

14.01.1997

5

Свекла

5

50

2

16.01.1997

6

Сливы

6

50

4

Рис. 1 16 Логическая структура индексов

Следовательно, если нужно выбрать все записи с наименованием товара "Свекла", нет нужды просматривать всю таблицу. Достаточно найти в индексе, построенном по столбцу "Наименование товара", первый указатель на запись, содержащую товар "Свекла", и считать из таблицы эту запись, а затем повторить то же для всех иных указателей в индексе на записи с товаром "Свекла". Если нужно считать все записи из таблицы, отвечающие условию "Количество > 16", достаточно найти в индексе, построенном по столбцу "Количество", первую строку с количеством больше 16, считать запись из таблицы по указателю на нее, записанному в индексе, и в дальнейшем повторить эти действия для всех записей, у которых значение "Количество" в индексе больше 16.

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

В описанном выше нехитром примере использования индексов мы сталкиваемся с двумя методами доступа к записям в таблице - последовательным и индексно-последовательным. При этом индексно-последовательный доступ неявно использует прямой и последовательный доступ.

При последовательном методе доступа для выполнения запроса к таблице БД просматриваются все записи таблицы, от первой к последней. Нет смысла говорить, что этот метод совершенно неэффективен (зачем просматривать 100 000 записей, если удовлетворяют условию запроса всего 2?). Неэффективность выражается прежде всего в потери быстродействия и напрасной трате вычислительных ресурсов. Время выполнения запроса прямо пропорционально числу записей в таблице.

При индексно-последовательном методе доступа

для выполнения запроса к таблице БД указатель в индексе устанавливается на первую строку, удовлетворяющую условию запроса (или его части), и считывается запись из таблицы по хранящемуся на нее в индексе указателю. Затем указатель в индексе перемещается на следующую строку, удовлетворяющую условию запроса (или его части), и из таблицы считывается запись. То же происходит для всех строк в индексе, удовлетворяющих условию запроса (или его части). Процесс выборки прекращается, когда текущая строка в индексе перестанет удовлетворять условию запроса.

Заметим, что оговорка "удовлетворяющих условию запроса (или его части)" сделана специально, поскольку запросы, состоящие из более чем одного критерия поиска записей, приходится удовлетворять за несколько обращений с индексу. Например, для запроса, "выдать все приходы свеклы или картофеля" может потребоваться сначала отыскать все записи по приходу свеклы, а затем по приходу картофеля.

При индексно-последовательном доступе просматривается только часть индекса, а из таблицы читаются только записи, удовлетворяющие условию поиска. Метод назван индексно-последовательным потому, что:

• поиск ведется по индексу, а не по самой таблице;

• поиск в индексе начинается только с первой строки, удовлетворяющей условию запроса или его части (так называемый прямой доступ);

• строки в индексе, начиная с такой записи, просматриваются все-таки последовательно.

В том случае, если в условия запроса входят поля, по которым не построено индексов, ищется иной пригодный индекс; если такого индекса нет, производится последовательный перебор записей таблицы БД.

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

Таким образом, индексно-последовательный метод доступа использует прямой доступ при установке в индексе на первую строку, удовлетворяющую запросу или его части. После этого используется последовательный метод доступа для перемещения по строкам индекса.

Для "локальных" ("персональных") СУБД типа Paradox, dBase индексы хранятся отдельно от основной таблицы БД - в виде отдельного файла. В случае их определения в "промышленных" ("серверных") СУБД - таких как Oracle, Sybase, InterBase, SQL Server - индексы хранятся вместе с БД.

Как уже сказано выше, определения первичных и внешних ключей таблиц БД приводят к созданию индексов по полям, объявленным в составе первичных или внешних ключей. Дополнительные индексы создаются вручную или программно, если индексов, построенных по определениям первичных и внешних ключей, недостаточно для:

• обеспечения нужного порядка сортировки данных;

• оптимизации доступа к базе данных.



Нормализация таблиц при проектировании базы данных


При проектировании структуры новой БД определяют сущности (объекты, явления) предметной области, которые должны найти свое отражение в базе данных. Анализ предметной области обычно осуществляется:

• на основании существующих сведений о предметной области в широком или в узком смысле, то есть в масштабах, в которых она должна быть представлена в создаваемой БД и работающих с ней приложениях;

• исходя из целей проектирования программной системы;

• на основании представления о том, какое место БД и работающие с ней приложения займут в структуре эксплуатирующей ее организации;

• на основании представлений о том, какие изменения деловых потоков организации последуют после внедрения программной системы в эксплуатацию.

В конечном итоге анализ предметной области должен привести к созданию эскиза БД. Сначала желательно изобразить сущности и связи между ними. Как правило, каждой сущности в БД соответствует таблица. Затем - в эскизе второго порядка - для каждой таблицы БД приводится список полей записи.

Замечание.

Несмотря на существование методик анализа предметных областей, построения эскизов БД (весьма полезных при больших объемах обрабатываемых данных и деловых правил в предметной области, нередко выходящих за рамки одновременного восприятия), необходимо отметить следующее:

• процесс определения окончательной структуры БД является циклическим, то есть на разных этапах проектирования - начиная от эскиза структуры БД и заканчивая опытной или даже промышленной эксплуатацией готовых программных систем - приходится возвращаться к структуре БД и вносить в нее изменения;

• в процессе моделирования предметной области участвуют такие субъективные факторы, как здравый смысл разработчика, его интуиция, привычки, личностное восприятие проблемы, стереотипы мышления и т.д. Поэтому различные разработчики наверняка предложат различные проекты структуры одной и той же БД, хотя в узловых моментах, например, в определении большей части сущностей и связей между ними, эти проекты должны быть похожи. Следовательно, с одной стороны, процесс проектирования структур БД является процессом творческим, неоднозначным, с другой стороны, узловые его моменты могут быть формализованы.

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

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

Существует несколько нормальных форм - 1НФ, 2НФ, ЗНФ, 4НФ, ЗНФ, нормальная форма Бойса-Кодда (БКНФ). При практической разработке баз данных важны первые три - 1НФ, 2 НФ, ЗНФ.

Первая нормальная форма (1НФ)

требует, чтобы каждое поле таблицы БД:

• было неделимым;

• не содержало повторяющихся групп.

Неделимость

поля означает, что значение поля не должно делиться на более мелкие значения. Например, если в поле "Подразделение" содержится название факультета и название кафедры, требование неделимости не соблюдается и необходимо из данного поля выделить или название факультета, или кафедры в отдельное поле.
Накладная №123
Дата

Покупатель Адрес
10.01.97

ТОО "Геракл" г. Москва , ул. Стромынка , 20
Отпущен товар Количество ед.изм. Цена ед.изм. Общая стоимость
Тушенка 10000 банки 7000 70 000 000
Сахар 200 кг 5000 1 000 000
Макароны 1000 кг 3000 3 000 000
Итого 74 000 000

Повторяющимися

являются поля, содержащие одинаковые по смыслу значения. Например, если требуется получить статистику продаж четырех товаров по месяцам, можно создать поля для хранения данных о продаже по каждому товару. Однако в этом случае мы имеем дело с повторяющимися группами (рис. 1.17):

Замечание.

Дефис в заголовке таблицы не является обязательным требованием именования таблиц БД; просто таблицы именуются именно такимобразом в использованной автором программе формирования IDEF1X-диаграмм базы данных (Design/IDEF).

Однако, что делать, если товаров не 4, а 104? Конечно, можно определить столько полей, сколько товаров. Но как быть, если число товаров заранее не известно и по одной накладной может быть отпущено 2, а по другой- 772 товара? Реализовать запись с переменным числом полей в реляционных базах данных невозможно, поскольку запись таблицы реляционной БД должна иметь четкую структуру. Исходя из вышесказанного, повторяющиеся группы следует устранить. В результате получим запись, содержащую информацию о статистике продаж по одному товару (рис. 1.18). Для 4 товаров будем иметь 4 записи, для 104 товаров - 104 записи и для n товаров - n записей для каждого месяца.

Пример.

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

В начале проектирования, приводя данные к первой нормальной форме, сведем имеющиеся данные в одну таблицу. Известно, что впоследствии будет необходимо производить анализ продаж по городам. Поэтому из поля "Адрес" (допускающего толкование как делимого поля) выделим в отдельное поле "Город". Известно, что каждый покупатель может закупить в один день различное количество товаров. Поэтому переборем искушение назначить каждому товару отдельное поле и выделим факт отпуска товара в отдельную запись (рис. 1.19). Для того, чтобы продолжить нормализацию данных, приведем данные ко второй нормальной форме (2НФ).

Вторая нормальная форма (2НФ)

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

Продолжим рассмотрение описанного выше примера. Для приведения к 2НФ выделим поля, которые входят в первичный ключ. Дата накладной и номер накладной по отдельности не могут уникально определять запись, поскольку они будут одинаковы для всех записей, относящихся к одной и той же накладной. Поэтому введем в первичный ключ поле "Товар". При этом исходим из имеющегося правила, что по одной накладной может быть отпущено одно наименование конкретного товара, то есть не может иметь место ситуация, когда отпуск одного и того же товара оформляется в накладной двумя строками (что влечет за собой две одинаковые записи в таблице "Отпуск товаров со склада"):

Дата Покупатель Адрес

10.01.97

ТОО "Геракл" г. Москва , ул. Стромынка, 20
Отпущен товар Количество ед. изм. Цена ед.изм . Общая стоимость
Тушенка 6000 банки 7000 42 000 000
Тушенка 4000 банки 7000 28 000 000
Сахар 200 кг 5000 1 000 000
Макароны 1000 кг 3000 3 000 000
Итого 74 000 000

Покажем на рис. 1.20. структуру таблицы "Отпуск товаров со склада" после выделения полей в составе первичного ключа (эти поля отчеркнуты от прочих полей линией и располагаются в верхней части структуры таблицы).

Проведя смысловой анализ зависимостей между полями таблицы, нетрудно увидеть, что созданный нами первичный ключ является избыточным: поле "Номер накладной" однозначно определяет дату и покупателя. Для данной накладной не может быть никакой иной даты и никакого иного покупателя.

Поле "Товар", будучи взято в комбинации с номером накладной, напротив, однозначно идентифицирует запись, поскольку для каждой записи ясно, о каком, собственно, товаре из множества товаров, отпущенных по данной накладной, идет речь. После уточнения состава полей в первичном ключе получим таблицу со структурой, показанной на рис. 1.21.

Первое требование 2НФ выполнено. Чего не скажешь о втором требовании, гласящем, что значения всех полей записи должны однозначно зависеть от совокупного значения первичного ключа и не должна иметь место ситуация, когда некоторые поля зависят от части первичного ключа. Действительно, при дальнейшем анализе можно увидеть, что поля "Единица измерения", "Цена за единицу измерения" зависят только от значения поля "Товар". В самом деле, стоимость единицы измерения товара и название самой единицы измерения не зависят от конкретной накладной и будут одинаковыми для всех накладных, в которые входит данный товар. Поэтому выделяем данные поля в отдельную таблицу "Товары" и определяем связь: поскольку один товар может присутствовать во многих накладных, таблицы "Товары" и "Отпуск товаров со склада" находятся в связи "один-ко-многим" (рис. 1.22.).

После анализа структуры таблицы "Отпуск товаров со склада" можно заметить, что значение поля "Покупатель" никоим образом не зависит от пары значении "Номер накладной", "Товар", а зависит только от значения поля "Номер накладной". Поэтому данное поле и зависящие от его значения поля "Город", "Адрес" выделяются в отдельную таблицу "Покупатели" (рис. 1 23.)

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

Установим связи между таблицами Один покупатель может встречаться во многих накладных. Поэтому между таблицами "Покупатели" и "Накладные" имеется связь "один-ко-многим" по полю "Покупатель". Одной накладной может соответствовать несколько товаров Поэтому между таблицами "Накладные" и "Отпуск товаров со склада" имеется связь "один-ко-многим" по полю "Номер накладной" (рис 1 25).

Для того чтобы уяснить, до конца нормализованы таблицы в составе разрабатываемой нами БД или нет, проанализируем ее структуру с позиций третьей нормальной формы (ЗНФ)

Третья нормальная форма

(ЗНФ) требует, чтобы в таблице не имелось Транзитивных зависимостей между неключевыми полями, то есть чтобы значение любого поля таблицы, не входящего в первичный ключ, не зависело от значения другого поля, не входящего в первичный ключ.

Продолжим рассмотрение примера. Можно увидеть, что в таблице "Отпуск товаров со склада" имеется зависимость значения поля "Общая стоимость" от значения поля "Количество". Значение поля "Общая стоимость" может вычисляться как значение поля "Количество", умноженное на значение поля "Цена за единицу измерения" из таблицы "Товары" (из записи с таким же значением поля "Товар"). Поэтому поле "Общая стоимость" из таблицы "Отпуск товаров со склада" удаляем В результате получаем нормализованную базу данных, структура которой приводится на рис. 1 26.

Замечание.

В таблице "Покупатели" значение поля "Адрес" зависит от значения поля "Город", поскольку в разных городах могут оказаться улицы с одинаковыми названиями и, соответственно, дома с одинаковыми номерами (вспомним известный кинофильм "Ирония судьбы, или с легким паром"). Думается, что такой зависимостью можно пренебречь, поскольку поле "Адрес" в нашем случае носит чисто информационный характер и не должно входить в условия запросов самостоятельно. Вообще говоря, на практике не всегда возможно получить идеально нормализованную БД. Часто к этому и не стремятся - по причинам, изложенным в следующем разделе.

Нормализация - за и против


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

Однако у нормализованной БД есть и недостатки, прежде всего практического характера.

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

Другим недостатком нормализованной БД является необходимость считывать из таблиц связанные данные при выполнении запросов к нескольким таблицам БД. Так, например, пусть для рассмотренной выше БД, содержащей сведения о расходе товара со склада, требуется выдать отчет, в котором для каждой накладной указан покупатель и его реквизиты (город и адрес). Для этого необходимо каждую запись в таблице "Накладные" объединить по названию покупателя (поле связи) с соответствующей записью из таблицы "Покупатели". Операции такого объединения подразумевают поиск и позиционирование в таблице "Покупатели" и могут выполняться достаточно медленно, особенно когда одна из таблиц имеет большой объем, данные в базе данных и на диске фрагментированы, и т.д. Замечено, что ненормализованные (скажем так: "не вполне нормализованные") данные отыскиваются быстрее, если они хранятся в одной таблице, по сравнению со случаем поиска данных в одной или более связанных таблиц. Подобное ускорение тем заметнее, чем больше число записей в связанных таблицах. На скорость поиска в подчиненной таблице могут оказывать негативное влияние такие факторы, как слишком

большое число вложенных полей в индексе; индекс, структура которого не совсем корректно определена, и другие факторы.

Приведенные выше соображения не следует воспринимать как призыв вовсе не нормализовывать данные. Эти соображения лишь призваны показать, что при работе с данными большого объема приходится искать компромисс между требованиями нормализации (то есть "логичности" данных и экономии места на носителях информации) и необходимостью улучшения быстродействия системы.



Понятие транзакций


Под транзакцией понимается воздействие на БД, переводящее ее из одного целостного состояния в другое. Воздействие выражается в изменении данных в таблицах базы.

Если одно из изменений, вносимых в БД в рамках транзакции, завершается неуспешно, должен быть произведен откат к состоянию базы данных, имевшему место до начала транзакции. Следовательно, все изменения, внесенные в БД в рамках транзакции, либо одновременно подтверждаются, либо не подтверждается ни одно из них.

Разберем пример. Рассмотренную выше нормализованную БД, содержащую сведения об отпуске товаров со склада, дополним двумя таблицами (рис. 1.27):

"Статистика по товару" - содержит сведения о суммарном отпуске каждого товара со склада, начиная с начала года;

• "Статистика по покупателю" - содержит сведения о суммарном отпуске

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

• добавление записи в таблицу "Отпуск товаров";

• отыскание записи по данному товару в таблице "Статистика по товару" и увеличение значения поля "Всего отпущено товара" на значение "Отпущено ед."; если запись по такому товару в таблице "Статистика по товару" отсутствует, она должна быть добавлена;

• отыскание записи по данному покупателю в таблице "Статистика по покупателю"; вычисление стоимости отпущенного товара и увеличение на это значение поля "Всего отпущено"; если запись по такому товару в таблице "Статистика по покупателю" отсутствует, она должна быть добавлена.

Рассмотрим случай отгрузки товара "Макароны" в количестве 100 кг по цене 3000 за кг покупателю "Продбаза № 4". Если в рамках транзакции произошел сбой по одной из операций, необходимо отменить результаты выполнения всех других операций, иначе информация в БД будет недостоверной.

Если произошел сбой на добавлении записи в таблицу "Отпуск товаров", выполнение других операций приведет к увеличению статистики в соответствующих таблицах по товару "Макароны" на 3000 кг и по покупателю "Продбаза № 4" на 300 000 руб, хотя в действительности сведения о такой отгрузке в таблице "Отпуск товаров" будут отсутствовать.

Если произошел сбой при увеличении поля "Всего отпущено товара" в таблице "Статистика по товару", а другие операции завершились успешно, значения в таблице "Статистика по товару" окажутся недостоверны, поскольку в ней не будет отражен один из фактов расхода товара "Макароны".

Если произошел сбой при записи в таблицу "Статистика по покупателю", а другие операции завершились успешно, данная таблица будет содержать недостоверные сведения о сумме отпуска товаров покупателю "Продбаза № 4"

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

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

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



Типы таблиц БД по виду их изменения -справочные, операционные и транзакционные


Разные таблицы БД различаются по способу формирования в них информации и по типу их изменения в процессе работы с приложениями, обеспечивающими доступ к этой БД. Можно выделить три типа основных таблиц по способу формирования в них значений и их дальнейшего использования.

Справочные таблицы -

содержат информацию справочного характера, обладающих невысокой степенью изменчивости по сравнению с таблицами БД других видов; как правило, находятся с операционными и транзакционными ТБД в отношении "один-ко-многим", являясь при этом родительскими таблицами.

В рассматриваемой нами БД, содержащей информацию об отпуске товаров со склада, справочными таблицами являются "Товары" и "Покупатели". Приложение для операций с БД должно быть спроектировано таким образом, чтобы всякий раз, когда в другие таблицы необходимо внести название товара или покупателя, выбор производился из текущего содержимого указанных справочных таблиц. Это необходимо для того, чтобы значения полей связи и в родительских (т.е. справочных), и в дочерних таблицах (например, "Накладные", "Отпуск товаров со склада") были идентичны.

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

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

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

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

В рассматриваемом нами примере в качестве операционных выступают таблицы "Накладные" и "Отпуск товаров со склада". В них ежедневно добавляется информация о отпуске товаров со склада. Занесение данных в эти таблицы вызывает одновременные или периодические изменения в транзакционных таблицах "Статистика по товару" и "Статистика по покупателю".

Транзакционные таблицы

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

транзакционных таблиц зависят от конкретной реализации системы и могу! выполняться приложением или СУБД по заданным правилам (бизнес-правила, триггеры и т.д.).

В нашем примере в качестве транзакционных выступают таблицы "Статистика по товару'.' и "Статистика по покупателю". Информация в них формируется на основании данных в операционных таблицах "Накладные" и "Отпуск товаров со склада".



Типы информационных систем


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

Например, в рассматриваемой нами системе обработки сведений о отпуске товаров со склада в таблицы "Накладные" и "Отпуск товаров со склада" ежедневно поступает итоговая информация. На выходе могут выдаваться сведения о суммарных оборотах по всему складу, по конкретному товару, покупателю, городу, обобщенные данные о приросте расхода того или иного товара, о динамике роста или уменьшения сроков хранения товара на складе и т.д.

Можно выделить два различных принципа формирования итоговой информации в информационных системах.

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

Главным преимуществом такого подхода является возможность практически немедленной выдачи итоговых данных по любому интересующему нас периоду, поскольку большинство расчетов для этого уже произведено при добавлении в БД исходной информации. К недостаткам можно отнести, как правило, трудоемкую реализацию таких алгоритмов, необходимость расходования ресурсов на накапливание промежуточных данных в момент добавления информации, необходимость обеспечения отказоустойчивости в работе и восстановления (то есть повторных расчетов) при сбоях.

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

- более понимаемой. Однако эти достоинства влекут за собой главный недостаток

- для формирования итоговых данных часто требуются значительные вычислительные и временные ресурсы.

В приводимой нами системе элементы первого подхода можно проследить в структуре БД, в которой присутствуют таблицы "Статистика по товару" и "Статистика по покупателю". Без данных таблиц можно обойтись, однако в этом случае получение итоговых сведений придется приводить по второму

варианту.

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



Навигационный и SQL-ориентированный подходы к операциям над данными


Существует два основных подхода к операциям над данными в ТБД.

Навигационный подход

ориентирован на обработку каждой записи таблицы в отдельности. Этот подход используется в так называемых локальных (персональных, настольных) базах данных типа Paradox и dBase.

При SQL-ориентированном подходе происходит обработка групп записей (этот подход часто называют ориентированным на множества записей или на наборы данных). При этом могут обрабатываться записи нескольких таблиц БД. Такой подход используют так называемые "серверные" (промышленные, удаленные) базы данных - такие как Oracle, Sybase, Informix, InterBase и др. О различиях локальных и удаленных БД будет рассказано в следующих разделах.



Фаза


Запускается транзакция БД;

Кэшированные изменения записываются в БД.



Постановка задачи


Требуется создать в среде Delphi приложение, предназначенное для учета поступающих на склад товаров. База данных состоит из двух таблиц: справочника "Товары" и операционной таблицы "Приход товаров". Таблицы необходимо создать и хранить в формате Paradox. Отношение между таблицами "один-ко-многим", то есть одному товару в таблице "Товары" может соответствовать более одной записи в таблице "Приход товаров". Рабочая структура таблиц приведена на рис. 2.1

Для таблицы "Товары" первичный ключ построен по полю Tovar. Для таблицы "Приход товаров" первичный ключ построен по полю N_Prih Для реализации ссылочной целостности (с таблицей "Товары") необходимо построить внешний ключ по полю Tovar. Для сортировки записей при их выводе в приложении необходимо создать индекс по полям "Дата прихода", "Товар".



Создание псевдонима базы данных


При работе с таблицами локальных баз данных (в число которых входят таблицы СУБД Paradox и dBase) базой данных считается каталог на диске, в котором хранятся файлы таблиц БД, индексов, примечаний (мемо-полей) и т.д. Для хранения одной таблицы создается отдельный файл. Такие же отдельные файлы создаются для хранения индексов таблицы и мемо-полей.

Обращение к БД из утилит и программы осуществляется по псевдониму (алиасу, alias) базы данных. Такой псевдоним должен быть зарегистрирован в файле конфигурации конкретного компьютера при помощи утилиты BDE Administrator.

Пусть наша база данных будет находиться в каталоге "D:\PROBA". Присвоим псевдоним создаваемой БД. Пусть имя этого псевдонима будет "PROBA". Запустим утилиту BDE Administrator. Выберем в главном меню Элемент Object \ New. В появившемся окне (рис. 2.2) оставим тип создаваемой БД без изменений (STANDARD) и нажмем Ok.

В левом окне появившегося окна администратора БД мы увидим строку с именем STANDARDl. Изменим это имя на "PROBA". Для этого щелкнем мышью на названии БД и введем новый текст.

В правом окне приведены параметры БД. Оставим их без изменения, изменив лишь PATH. Этот параметр указывает путь к каталогу, в котором будет расположена БД. Можно ввести путь вручную, но лучше воспользоваться средствами администратора: для этого нужно щелкнуть по полю PATH и нажать на появившуюся в правом углу поля кнопку. Затем следует выбрать каталог D:\PROBA и нажать кнопку Ok (рис. 2.3.).

Теперь необходимо запомнить определение псевдонима. Для этого в левом окне администратора БД необходимо щелкнуть по имени псевдонима правой кнопкой мыши и во всплывающем меню выбрать элемент Apply. В появившемся диалоговом окне, в котором спрашивается, собираемся ли мы запоминать изменения для псевдонима, необходимо нажать кнопку Ok. Затем следует выйти из утилиты BDE Administrator. Теперь создание псевдонима завершено и к нему можно обращаться из других утилит и приложений. Однако каталог, на который ссылается псевдоним БД, еще пуст. Необходимо создать таблицы базы данных.



Объявление полей


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

Для установки рабочего псевдонима нужно выбрать элемент главного меню File | Working Directory и в выпадающем списке A liases выбрать имя псевдоним PROBA, после чего нажать кнопку Ok.

Для создания таблицы БД нужно выбрать элемент главного меню File \ New | Table. В появившемся окне Create Table оставляем без изменения тип создаваемой таблицы (Paradox 7) и нажимаем кнопку Ok. После этого появится окно определения структуры таблицы БД (рис. 2.4).

Каждая строка таблицы соответствует полю. Назначения столбцов:

• Fields Name - имя поля;

• Type - тип поля;

• Si:e - размер поля (для строковых полей, поскольку иные поля подразумевают размер, определяемый типом поля);

• Key - содержит звездочку '*', если поле входит в состав первичного ключа. Если в первичный ключ входит несколько полей, они должны определяться в той последовательности, в которой они присутствуют в первичном ключе. Кроме того, все поля, входящие в состав первичного индекса, должны определяться перед иными полями, то есть быть в списка полей наверху.

Определим поля, входящие в таблицу "Товары". Введем Tovary в столбец Field Name. Для того, чтобы определить тип поля, щелкните по столбцу Type и нажмите клавишу пробела. В ответ на это будет выдан список типов полей, из которых необходимо произвести выбор нужного типа (рис. 2.5).

Рис. 2.5. Выбор типа поля

Рассмотрим возможные типы полей СУБД Paradox:
Тип поля Обозначение Хранимые значения
Alpha A Символьные значения длиной до 255 символов.
Number N Числовые значения с плавающей точкой в диапазоне -10307...+10308. Точность до 15 значащих цифр.
Money $ Аналогичен типу Number, но предназначен для хранения денежных сумм. Число знаков после запятой по умолчанию - 2. При показе значения выводится знак денежной единицы.
Short S Целочисленные значения в диапазоне -32 767..32 767.
LongInteger I Целочисленные значения в диапазоне -2 147 483 648 ..2 147 483 647.
BCD # Числовые значения, в том числе и дробные, в двоично-десятичном формате. Обеспечивает исключительную точность при работе с большим числом знаков в дробной части. Применяется в вычислениях, где важна точность (финансовые, научные приложения). Для проведения вычислений требует больше времени, чем для числовых полей иных типов.
Date D Значения даты (в диапазоне от 01.01.9999 до н.э. до 31.12.9999).
Time T Значения времени.
Timestamp @ Значения даты и времени.
Memo M Строковые значения длиной более 255 символов. Максимальная длина не ограничена. От 1 до 240 символов могут храниться вместе с таблицей БД; остальные хранятся в виде Memo-файла (расширение .MB)
Formatted Memo F Аналогично мемо-полю, но, может хранить форматированные тексты, в которых фрагменты текста представлены разным шрифтом, цветом и стилями.
Graphic Fields G Графические изображения в формате файлов -BMP, .PCX, -TIF, .GIF, .EPS, которые при хранении преобразуются к формату .BMP. Хранятся отдельно от основной таблицы БД.
OLE 0 Информация в форматах, поддерживаемых технологией OLE (Object Linking and Embedding) фирмы Microsoft
Logical L Логические значения ("True", "False"). Высота букв не имеет значения.
Autoincrement ± Автоинкрементное поле. Значения доступны только для чтения. Обычно - ключевое поле в составе первичного ключа. При добавлении новой записи значение поля вычисляется автоматически таким образом, чтобы в одной и той же таблице не было одинаковых значений. Значения поля из удаленных записей повторно не используются
Binary В Произвольные двоичные значения. Должны интерпретироваться приложениями пользователя. DBD не интерпретирует значения этих полей. Хранятся в отдельных от основной таблицы .МВ-файлах. Длина не определена
Bytes Y Произвольные двоичные значения, интерпретируемые приложениями пользователя, длиной от 1 до 240 байт. Хранятся вместе с таблицей БД.

Для того, чтобы определить тип поля Tovar, выберем А /рпа и затем в столбце Sire укажем значение 20. В столбце Key поместим звездочку, означающую, что данное поле входит в состав первичного ключа. Для этого нажмем любой символ на клавиатуре. Повторное нажатие любого символа снимает отметку звездочкой в столбце Kеу.

Введем определения и других столбцов таблицы Tovary (рис. 2.6). Для каждого поля определим требование обязательного заполнения поля значением. Для этого, переходя от поля к полю, включим переключатели Required Field. Другие поля служат для наложения ограничений на значение поля:

• Minimum value - определяет минимальное значение поля, Maximum value - определяет максимальное значение поля;

Default value -

определяет значение поля по умолчанию;

• Picture - определяет шаблон изображения поля. Для формирования шаблона следует нажать кнопку Assist.

Отсутствие значения в одном из полей означает отсутствие ограничений на значение поля.



Запоминание таблицы


Чтобы запомнить сохраненную таблицу на диске, следует нажать кнопку Save As. Затем в появившемся окне следует указать имя таблицы (рис. 2.7). При желании можно указать каталог или псевдоним, отличные от принятых по умолчанию. Напомним, что по умолчанию принимается рабочий каталог или каталог, определяемый рабочим псевдонимом.

После того, как мы определим имя создаваемой таблицы (Tovary), в каталоге С \PROBA (он назначен псевдониму PROBA, используемому нами в качестве рабочего псевдонима) будет создан файл Tovary.DB и файлы индексов с соответствующими расширениями.



Изменение структуры существующей таблицы


Если в структуру существующей таблицы БД необходимо внести изменения, следует выбрать элемент меню File | Open | Table, в появившемся диалоговом окне выбрать имя таблицы и нажать кнопку Ok. Будет показано содержимое таблицы (на рис. 2.8: в таблице Tovary отсутствуют записи, что не удивительно, поскольку мы их еще не вводили).

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

Чтобы изменить структуру таблицы, выберите элемент меню Table | Restructure. Вслед за этим будет показано диалоговое окно для определения структуры таблицы.



Определение индексов


Определим структуру таблицы "Приход товаров" (рис. 2.9).

Всем полям назначим атрибут Required (требование обязательного существования значения у поля на момент его запоминания в БД), кроме поля N_Prih:, поскольку это поле автоинкрементное, заполнение его значением производится автоматически при запоминании новой записи.

Создадим индекс по полям "Дата прихода", "Товар". Для этого в комбинированном списке Table Properties (в правом верхнем углу окна) выберем элемент Secondary Indexes. После этого диалоговое окно приобретет вид, показанный на рис. 2.10.

Чтобы определить новый индекс, нажмем кнопку Define. В появившемся диалоговом окне в поле Fields содержится список полей определяемой нами таблицы. Поле Index Fields предназначено для хранения полей, входящих в создаваемый индекс. Чтобы скопировать конкретное поле из списка Fields в список Index Fields, нужно нажать кнопку с изображением правой стрелки. Последовательность добавления полей в список важна, она определяет порядок чередования полей в списке. После того, как мы поместили нужные поля в список Index Fields (рис. 2.11), нажмем кнопку Ok.

В появившемся окне запрашивается имя индекса (рис. 2.12) Следует ввести имя и нажать Ok.

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

Как видно на рис.2.13, после добавления нового индекса его имя появилось в списке индексов.

Впоследствии, щелкнув по имени индекса, мы можем его удалить (кнопка Erase) или изменить (кнопка Modify).

Сохраним созданную нами таблицу под именем Pnhod.



Определение ссылочной целостности между таблицами


Как известно из постановки задачи, таблицы "Товары" и "Приход товаров" находятся в отношении "один-ко-многим", то есть с одной записью в таблице Tovary может быть связано несколько записей по приходу того же товара в таблице Prihod. В качестве поля связи выступает поле Tovar, присутствующее в обеих таблицах.

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

Откроем таблицу Prihod (элемент меню File \ Table \ Open) и затем войдем в режим изменения структуры таблицы (Table \ Restructure). В выпадающем списке Table Properties выберем элемент Refrential Integrity и нажмем кнопку Define. В появившемся диалоговом окне (рис. 2.14) в списке Fields показаны поля таблицы Prihod, а в списке Tables - таблицы базы данных PROBA.

Выберем в списке Fields поле Tovar и нажмем кнопку с изображением стрелки вправо. Название Tovar будет записано в поле Child Fields (поле внешнего ключа дочерней таблицы).

Выберем в списке Tables таблицу Prihod и нажмем кнопку с изображением стрелки влево. В поле Parents Key (ключ родительской таблицы) будут показаны поля из первичного ключа таблицы Tovary В данном случае это поле Tovar.

Переключатели Update rules определяют вид каскадных воздействий на таблицу Prihod при изменении значения поля связи в таблице Tovary или при удалении записи в таблице Tovary:

• Cascade - каскадные изменения и удаления подчиненных записей в таблице Prihod;

• Prohibit - запрет на изменение поля связи или удаление записи в таблице

Tovary, если для данной записи есть связанные записи в таблице Prihod. Выберем Cascade (рис. 2.15) и нажмем кнопку Ok.

Будет запрошено имя - в Paradox ссылочные целостности именуются. Введем имя, например Tovary_Prihod_Integnty, и нажмем кнопку Ok. Теперь имя созданной ссылочной целостности будет помещено в список.

Запомним изменения в таблице Prihod (кнопка Save) и заново войдем в режим реструктуризации таблицы Prihod (Table | Restructure). В выпадающем списке Table properties выберем элемент Secondary Indexes (индексы таблицы, кроме индекса, построенного по определению первичного ключа). В списке индексов увидим, что появился новый индекс с именем Tovar (по полю Tovar). Этот индекс построен автоматически по неявному определению внешнего ключа при создании ссылочной целостности (рис. 2.16).

Выйдем из режима реструктуризации и покинем DBD. После этого перейдем к разработке простейшего приложения для работы с созданными таблицами.



Создание простейшего приложения


Создадим в каталоге CAPROBA подкаталог АРР. В нем мы будем хранить разработанные приложения.

Запустим Delphi. По умолчанию Delphi при своем запуске создает форму для нового приложения. Воспользуемся ею. В палитре компонентов Delphi на странице Data Access выберем мышью невизуальный компонент TTable (рис. 2.17), щелкнем на нем мышью и затем щелкнем мышью в форме. После этого, изображение компонента останется в форме.

Невизуальным компонент TTable (как и другие компоненты, например, TQuery, TDataSource) называется потому, что он применяется для хранения и доступа к данным, а не для их визуализации - для этой цели применяются визуальные компоненты (TDBGrid, TEdit и другие).

После того, как мы разместили в форме компонент TTable, установим его свойства. Для этой цели воспользуемся инспектором объектов (Object Inspector), который обычно помещается слева от формы. Если он не видим, его можно вызвать, нажав кнопку F11. Инспектор объектов позволяет устанавливать свойства того компонента в форме, который выделен при помощи мыши. Выделим мышью компонент TTable.

Установим значение свойства DatabaseName (псевдоним БД) в PROBA при помощи выпадающего списка или введя его вручную. Установим значение свойства TableName (имя таблицы БД) в Tovary.DB при помощи выпадающего списка. После этого установим значение свойства Active в True. После этого произойдет реальное связывание компонента TTable (он по умолчанию имеет имя Tablel) с реально существующей таблицей Tovary.DB.

Компонент TTable и компонент TQuery (его мы рассмотрим позже) служат для хранения наборов данных. Понятие набора данных несколько шире, чем понятие таблицы БД, поскольку набор данных может содержать:

• подмножество записей или полей таблицы БД (компоненты TTable, TQuery);

• записи, сформированные из нескольких таблиц БД (компонент TQuery). Расположим в форме компонент TDataSource. Он служит в качестве связующего звена между невизуальными компонентами (в данном случае Tablel) и визуальными компонентами, которые мы добавим в форму позднее. Поэтому компоненты TDataSource часто называют источниками данных. Установим свойство DataSef (имя набора данных) компонента TDataSource в значение Tablel путем выбора из выпадающего списка.

Расположим в форме компонент TDBGrid, взяв его из палитры компонентов (страница Data Controls). Установим свойство DataSource компонента TDBGrid в значение DataSource1 (это имя, присвоенное Delphi по умолчанию созданному нами перед этим компоненту TDataSource). Компонент TDBGrid служит для отображения записей набора данных в табличной форме.

Вид разрабатываемой формы представлен на рис. 2.18.

Выберем элемент меню File \ Save Project As и сохраним проект. Сначала запрашивается имя формы проекта (у нас форма одна, с именем Form1). Сохраним форму под именем 'appll.pas'. Затем запрашивается имя проекта. Сохраним проект под именем 'appl.dpr'.

После этого выполним приложение. (Чтобы выполнить приложение, не выходя из среды Delphi, достаточно нажать кнопку F9. Чтобы создать приложение и запустить его вне среды Delphi, следует нажать комбинацию кнопок Ctrl+F9 и затем запустить созданный файл с расширением .ехе и именем, совпадающим с именем проекта. В нашем случае следует запускать файл 'appl.exe').

Добавлять записи в набор данных (и, следовательно, в таблицу Tovary.DB) можно прямо из компонента TDBGrid.

Для добавления записи нужно нажать на клавиатуре кнопку Insert или, находясь на последней записи набора данных, кнопку "стрелка вниз". Набор данных автоматически перейдет в режим добавления новой записи. После ввода значений в поля записи запомнить запись в наборе данных можно, перейдя на другую запись при помощи клавиш управления курсором. Отказаться от запоминания записи можно, нажав кнопку Esc.

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

Для удаления записи следует установить на нее указатель текущей записи и нажать комбинацию кнопок Ctrl+Del.

На рис.2.19 показан вид приложения в момент добавления в таблицу Tovary новой записи.



Создание приложения для работы с двумя таблицами


Покажем, как в одной форме можно связать два набора данных (родительский и подчиненный) так, чтобы в подчиненном наборе данных всегда показывались записи, соответствующие текущей записи в родительском НД

Сохраним форму приложения в файле 'app21.pas', а проект приложения - в файле 'арр2 drp' Добавим в приложение компонент TTable (с именем Table2) для работы с таблицей Prihod базы данных PROBA (значения свойств такие же, как у компонента Tablel, но свойство TableName ссылается на имя таблицы Prihod DB) Установим свойство Table2 Avtive в True Добавим в форму компонент TDataSource (имя по умолчанию DataSource2). Установим свойство DataSet этого компонента в значение Table2. Разместим в форме компонент TDBGnd (имя по умолчанию DBGrid2) и установим его свойство DataSource в значение DataSource2 (рис 2 20).

Запустим приложение на выполнение. Ввод и изменение данных в таблицу Prihod будем производить также из компонента TDBGnd (рис 2 21)

Обратите внимание, значение поля N_Prih формируется автоматически



Уточнение списка полей и настройка параметров столбцов в TDBGnd. Смена активного индекса


Как можно заметить, значение поля N_Prih необходимо для обеспечения уникальности в таблице Prihod и не несет никакой иной нагрузки. Поэтому данное поле лучше не показывать в составе столбцов DBGrid2. Для этой цели сформируем список полей таблицы Prihod В Delphi имеются две возможности указать, какие из полей таблицы БД следует использовать в приложении для набора данных (в нашем случае для компонента Table2)

Первый способ состоит в использовании по умолчанию всех полей из таблицы БД, с которой ассоциирован этот набор данных Этот способ всегда используется по умолчанию и, следовательно, был неявно использован и нами при создании наборов данных Tablel и Table2

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

Сохраним форму приложения как 'арр31.pas', а проект приложения как 'аррЗ.drp'. Выберем при помощи мыши компонент Table2 и нажмем правую кнопку мыши В появившемся на экране всплывающем меню выберем элемент Fields Editor В появившемся списке редактора полей (пока он пуст, рис 2 22 а) нажмем правую кнопку мыши и во всплывающем меню выберем элемент меню Add Fields Будет показан список всех полей таблицы БД Prihod.DB Отметим (при помощи мыши и кнопки Shift) все поля, кроме N_Prih (рис 2 22 б) и нажмем кнопку Add Теперь список редактора полей будет включать все отмеченные поля (рис 2 22 в)

Как можно заметить, в составе столбцов в компоненте DBGrid2 теперь присутствуют только те поля, которые добавлены для набора данных Table2 в редакторе полей (рис 2.23)

Определение для набора данных списка полей в редакторе полей приводит к тому, что для каждого добавленного таким образом поля в приложении Delphi автоматически создает компонент TField (поле набора данных) Каждый такой компонент по умолчанию именуется уникальным именем - в качестве первой составляющей имени поля берется имя набора данных (Table2), а в качестве второй составляющей - имя поля в таблице БД Так, компонент TField, соответствующий полю Tovar, будет поименован как Table2Tovar Если в редакторе полей щелкнуть по имени соответствующего поля, в инспекторе объектов можно установить или изменить свойства поля, а также определить обработчики события для конкретного поля Более подробно об этом сказано ниже в разделе, посвященном работе с полями.

Изменим параметры компонента DBGrid2 так, чтобы названия его столбцов содержали русские наименования Для этого щелкнем правой кнопкой мыши на компоненте DBGrid2, и во всплывающем меню выберем элемент Columns Editor На экране появится окно редактора столбцов компонента (рис 2 24 а) Для того, чтобы изменить характеристики столбцов в TDBGrid, нужно перейти от неявно определяемых столбцов к явно определяемым Для этого нужно щелкнуть по кнопке Add All Fields, в результате чего будут добавлены столбцы, каждый из которых соответствует полю, определенному в редакторе полей компонента Table2 (рис 2 24 б) Чтобы изменить заголовок каждого столбца, следует выбрать при помощи мыши имя столбца в редакторе столбцов, и в инспекторе объектов раскрыть список свойства Title (для чего следует щелкнуть мышью по крестику рядом с именем свойства) В элементе Caption этого списка содержится заголовок столбца, изменим соответствующим образом заголовки и затем выйдем из редактора столбцов DBGrid2 То же проделаем для набора данных Tablel (рис 2.25)

Рис 2.24 а) пустой список столбцов DBGrid2 6) заполненный список столбцов

Изменим также порядок сортировки записей в наборе данных Tdble2. Для этого в инспекторе объектов установим свойство Table2 Index FieldNames в значение 'DatPnh,Tovar' путем выбора из выпадающего списка, содержащего названия индексных полей, определенных для каждого существующего индекса таблицы Prihod DB. После этого войдем еще раз в редактор колонок DBGnd2 и при помощи мыши "перетащим" столбец DatPrih так, чтобы он предшествовал столбцу Tovar. Откомпилируем приложение и запустим его на выполнение. Как видно из рис. 2.26, набор данных Table2, ассоциированный с таблицей БД Prihod.DB, в приложении отсортирован по дате прихода, а внутри каждой даты прихода - по наименованию товара.



Определение визуальных компонентов для работы с полями записи набора данных


Сохраним форму приложения как 'арр41.pas', а приложение как 'app4.drp'. Теперь сделаем так, чтобы к полям записи в наборе данных Table2 можно было обращаться не только из сетки компонента DBGnd2, а из отдельных визуальных компонентов, позволяющих осуществлять доступ к отдельным полям записи набора данных.

Добавим в форму два компонента TDBEdit (палитра компонентов Data Controls). Разместим компонент DBEdit1 под столбцом "Дата прихода", а компонент DBEdit2 под столбцом "Количество" Определим поле, к которому можно иметь доступ через компонент DBEditl. Для этого установим значение его свойств - DataSource в DataSource2 и DataField в DatPrih. Определим поле, к которому можно иметь доступ через компонент DBEdit2 Для этого установим значение его свойств - DataSource в DataSource2 и DataField в Kolvo.

Для доступа к полю Tovar нам нужен более сложный компонент, который позволял бы вводить в поле Tovar таблицы Prihod.DB значения полей Tovar из таблицы Tovary.DB, и никакие другие значения. Для этой цели под столбцом "Товар" компонента DBGnd2 разместим компонент TDBLookupComboBox с именем по умолчанию DBLookupComboBox1. Установим свойства этого компонента.

• DataSource - в значение DataSource2,

• DataFiled - в значение Tovar,

• List Source - в значение DataSource 1

• LislField - в значение Tovar;

• Key Field - в значение Tovar

Добавим в приложение 5 компонентов кнопок TButton (страница Standard палитры компонентов). Изменим имена этих компонентов (свойство Name), используя инспектор объектов, соответственно на InsertButton, EditButton, DeleteButton, PostButton, EditButton. Изменим заголовки этих кнопок (свойство Caption), используя инспектор объектов, соответственно на "Добавить", "Изменить", "Удалить", "Запомнить", "Отменить" (рис. 2.27).

Выберем при помощи мыши кнопку InsertButton и два раза щелкнем на ней После этого мы перейдем в редактор кода и определим для кнопки InsertButton обработчик события нажатия кнопки, OnClick

procedure TForm1.InsertButtonClick(Sender: TObject);

begin

IF Table2.State = dsBrowse THEN

Table2.Insert; end;

Метод Insert переводит набор данных Table2 в состояние добавления записи dslnsert. Ввод значений полей осуществляется в компонентах DBEditl, DBLookupComboBoxl, DBEdit2 Для этого необходимо, чтобы набор данных находился в режиме просмотра dsBrowse.

Определим обработчик нажатия кнопки EditButton

procedure TFormI.EditButtonClick(Sender: TObject);

begin

IF Table2.State = dsBrowse THEN Table2.Edit;

end;

Метод Edit переводит набор данных Table2 в состояние добавления записи dsEdit. Редактирование значений полей осуществляется в компонентах DBEditl, DBLookupComboBoxl, DBEdit2 Для этого необходимо, чтобы набор данных находился в режиме просмотра dsBrowse

Определим обработчик нажатия кнопки DeleteButton

procedure TForm1.DeleteButtonClick(Sender: TObject);

begin

IF Table2.State = dsBrowse THEN

IF MessageDIg('Подтвердите удаление записи', mtConfirmation,[mbYes, mbNo],0) = mrYes THEN Table2.Delete/-

end;

Если набор данных Table2 находится в режиме просмотра записей dsBrowse, вызывается окно диалога (при выполнении функции MessageDIg), если пользователь нажимает кнопку Yes, происходит удаление текущей записи в наборе данных Table2

Определим обработчик нажатия кнопки PostButton

procedure TFormI.PostButtonClick(Sender: TObject);

begin

IF Table2.State in [dsInsert,dsEdit] THEN Table2.Post;

end;

Если набор данных находится в режиме добавления новой записи или редактирования, происходит выполнение метода набора данных Post, который запоминает текущее состояние записи в таблице БД После запоминания набор данных переводится в режим просмотра dsBrowse

Определим обработчик нажатия кнопки CancelButton

procedure TFormI.CancelButtonClick(Sender: TObject);

begin

IF Table2.State in [dslnsert,dsEdit] THEN Table2.Cancel;

end;

Если набор данных находится в режиме добавления новой записи или редактирования, происходит выполнение метода набора данных Cancel, который отменяет запоминание записи в таблице БД и переводит набор данных в режим просмотра dsBrowse

Для того чтобы набор данных нельзя было переводить в состояние добавления и изменения данных, а также удалять записи непосредственно из компонента DBGrid2, установим свойство DBGrid2 ReadOnly в значение True

После этого запустим приложение на выполнение. При добавлении новой записи или при корректировке существующей в поля можно заносить значения, используя ввод в компоненты DBEdit1, DBEdit2 и путем выбора из списка значений в компоненте DBLookupComboBoxl (рис 2.28). То же происходит при изменении записи. При удалении записи выдается окно диалога (рис 2.29)



Реализация связи Master-Detail между наборами данных


Нам известно, что таблицы базы данных Tovary.DB и Prihod.DB находятся в отношении "один-ко-многим". Поскольку мы определили ссылочную целостность между этими таблицами, можно сделать так, чтобы при установке указателя на запись в наборе данных Table1 (ассоциированном с Tovary. DB) в наборе данных Table2 (ассоциированном с Prihod.DB) показывались только записи прихода текущего товара в Table1. Это реализуется через механизм связи наборов данных Master-Detail.

Для этого откроем проект 'аррЗ.' В редакторе столбцов DBGrid2 сделаем столбец, соответствующий полю Tovary, первым по счету в DBGrid2.

В инспекторе объектов для компонента Table2 установим значение свойства MasterSource в DataSourcel. Переместимся на значение свойства MasterFields и нажмем кнопку эллипса. В появившемся окне Field Link Designer установим параметры связи. В -поле Available Indexes выберем в качестве текущего индекса по полю 'Tovar'. В списке Detail Fields выберем поле Tovar, в списке Master Fields выберем поле Tovar и нажмем кнопку Add. В поле Joined Fields будет сформировано выражение 'Tovar -> Tovar' (рис. 2.30). Нажмем кнопку Ok.

Как можно заметить, в компоненте Table2 текущий индекс (свойство Fieldlndex Names) заменен на индекс, построенный по полю 'Tovar'.

Выполним приложение. Теперь в наборе данных Table2 показываются только записи по приходу товара, текущего в наборе данных Table 1 (рис. 2.31). Мало того, при добавлении записи в набор данных Table2 значение поля Tovar по умолчанию берется равным значению поля Tovar из текущей записи в наборе данных Table1 (рис. 2.32).



Использование компонента TQuery для формирования набора данных из нескольких таблиц


Создадим новое приложение, выбрав в меню Delphi элемент File | New Application. Сохраним форму нового приложения как 'app51.pas', а само приложение как 'app5.dpr'.

Расположим в форме компонент TQuery (страница Data Access палитра компонентов). По умолчанию его имя Query1. Установим его свойство DatabaseName в PROBA. Расположим в форме компонент TDataSource (имя DataSource1). Установим его свойство DataSet в значение Queryl. Расположим в форме компонент TDBGrid. Установим его свойство DataSource в значение DataSourcel.

В инспекторе объектов для компонента Queryl найдем свойство SQL и нажмем кнопку эллипса. Затем в появившемся окне редактора наберем текст SQL-запроса

SELECT P.DatPrih, P.Tovar, P.Kolvo,Т.Zena, (P.Kolvo * Т.Zena) As Stoim

FROM Tovary T, Prihod P WHERE T.Tovar = P.Tovar ORDER BY P.DatPrih, P.Tovar

и нажмем кнопку Ok.

После этого установим свойство Queryl.Active в значение True. Набор данных Queryl содержит сведения о приходе товара со склада. В составе записи этого набора присутствуют поля DatPrih (дата прихода), Tovar (название товара), Kolvo (количество прихода), Zena (цена за ед. измерения данного товара), Stoim (стоимость прихода товара). Как видно из текста запроса в свойстве SQL, набор данных "собирается" из двух таблиц БД PROBA, Tovary.DB и Prihod.DB. При этом соединяются записи из этих таблиц БД, имеющие одинаковое значение поля Tovar (рис. 2.33)

Однако, стоит нам выполнить это приложение, и мы увидим, что в набор данных Queryl нельзя добавить новые записи и нельзя изменить или удалить существующие записи в наборе данных. Это происходит потому, что тип набора данных, "собираемого" более чем из одной таблицы БД, является доступным только для чтения.

* * *

Теперь, когда Вы попрактиковались в создании приложений Delphi, работающих с базами данных, перейдем к более детализированному рассмотрению визуальных и невизуальных компонентов Delphi для работы с данными. В следующем разделе показаны средства Delphi, доступные при разработке таких приложений, а также рассматриваются различные архитектуры приложений для работы с базами данных.



Фаза


В случае успешной записи кэшированных изменений в БД:

• происходит подтверждение транзакции БД;

• подтверждаются кэшированные изменения.

В случае неуспешной записи кэшированных изменений в БД:

• происходит откат транзакции БД;

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



С чего начать


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

Если Вы никогда не проектировали приложений для работы с базами данных в Delphi, приобретенный опыт поможет Вам понять, что построение таких приложений в Delphi максимально упрощено. Есть и еще одно последствие выполнения описываемых упражнений: читая в последующих разделах о средствах разработки приложений баз данных в Delphi, Вы будете встречать уже знакомые названия и понятия.



Общий обзор средств для работы с базами данных


В состав Delphi Client/Server Suite входят следующие средства для разрабо1ки и эксплуатации приложений, использующих базы данных:

• BDE (Borland Database Engine), машина баз данных фирмы Borland

Представляет собой набор библиотек. Должна устанавливаться на каждом компьютере, который использует приложения для работы с БД, написанные на Delphi. Выполняет действия по доступу к данным и проверке их правильности. Является, по существу, центральным средством для работы с БД из приложений, созданных с помощью Delphi.

•SQL Links

Драйверы для работы с удаленными "промышленными" СУБД, такими как Sybase, MS SQL Server, Oracle. Для работы с "родным" SQL-сервером Borland InterBase устанавливать SQL Links нет необходимости. Доступ к таблицам локальных ("настольных", "персональных") СУБД типа Paradox, dBase также осуществляется BDE напрямую, без использования SQL Links.

• BDE Administrator

Утилита для установки псевдонимов (имен) баз данных, параметров БД и драйверов баз данных на конкретном компьютере. При работе с БД из приложения, созданного с помощью Delphi, доступ к базе данных производится по ее псевдониму (имени). Параметры БД, определяемой псевдонимом, действуют только для этой БД; параметры, установленные для драйвера БД, действуют для всех баз данных, использующих драйвер. Кроме этого, в утилите BDE Administrator можно произвести установку таких общих для всех БД параметров, как формат даты и времени, форматы представления числовых значений, используемый языковый драйвер и т.д. Поддерживает информацию о конфигурации БД на конкретном компьютере в файле IDAPI32.CFG.

• Database Desktop (DBD)

Средство для создания, изменения и просмотра БД. Эта утилита прежде всего ориентирована на работу с таблицами локальных ("персональных") СУБД, таких как Paradox и dBase. В ряде случаев может использоваться и для работы с таблицами удаленных СУБД. Например, из DBD можно с некоторыми ограничениями создавать таблицы БД, работающих под управлением InterBase, Oracle, и просматривать их содержимое.

Общая модель взаимодействия приложения, реализованного с помощью Delphi, со средствами БД приведена на рис. 3.1.

• Database Explorer (SQL Explorer)

Утилита для конфигурирования псевдонимов БД, просмотра структуры БД, таблиц БД, выдачи запросов к БД, создания словарей данных.

•SQL Monitor

Средство для трассировки выполнения SQL-запросов.

• Visual Query Builder

Средство в составе интегрированной среды Delphi для автоматического создания SQL-запросов методом QBE (Query By Example, запрос по образцу).

• Data Dictionary

Словарь данных. Средство для хранения атрибутов полей таблиц БД отдельно от самих БД и приложений. Информация о полях может использоваться различными приложениями.

• Data Module

Невизуальные компоненты типа TDataModule применяются для централизованного хранения наборов данных в приложении, работающем с БД. Одним из главных удобств является приписывание каждому набору данных правил по управлению данными. Такие правила называются бизнес-правилами. Они обычно определяют реакцию системы при добавлении, изменении, удалении данных, при вводе ошибочных значений и реализуют блокировку действий, которые могут разрушить ссылочную и смысловую целостность БД.

Такие бизнес-правила, хранящиеся централизованно на уровне приложения, при использовании одного и того же набора данных в разных формах приложения, позволяют унифицировать поведение НД на уровне всего приложения.

• Object Repository

Репозиторий объектов Delphi. Будучи единожды разработанными для какого-либо приложения, формы с визуальными и невизуальными компонентами, а также компоненты TDataModule могут сохраняться в репозитории. Тогда они могут использоваться другими, вновь создаваемыми приложениями. Таким образом устраняется необходимость повторного написания идентичного или схожего кода в приложениях.

• Data Migration Wizard

Средство для перемещения данных между БД различных типов

• Невизуальные компоненты для работы с БД

Невизуальные компоненты Delphi служат для соединения приложения с таблицами БД. Они расположены на странице компонентов Data Access палитры компонентов в интегрированной среде разработки Delphi. Невизуальный компонент "перетаскивается" из палитры компонентов в форму разрабатываемого приложения. После этого Delphi автоматически описывает в форме экземпляр компонента указанного класса. Далее разработчик определяет свойства компонента, кодирует обработчики событий, где в программном коде вызывает необходимые ему методы компонента.

• Визуальные компоненты для работы с БД

Визуальные компоненты Delphi предназначены доя визуализации записей наборов данных (например, компонент TDBGrid) или отдельных полей текущей записи набора данных (например, TDBEdit, TDBText). Эти компоненты расположены на странице компонентов Data Controls палитры компонентов в интегрированной среде разработки Delphi. Визуальный компонент "перетаскивается" из палитры компонентов в форму разрабатываемого приложения. После этого Delphi автоматически описывает в форме экземпляр компонента указанного класса. Далее разработчик определяет соединение визуального компонента с невизуальными компонентами, определяет по необходимости различные свойства компонента, кодирует обработчики событий, где в программном коде вызывает необходимые ему методы компонента.

• Компоненты для построения отчетов

В интегрированной среде разработчика Delphi на странице палитры компонентов QReport размещено около двух десятков компонентов для построения отчетов. Их добавление в приложение происходит аналогично добавлению визуальных компонентов для работы с данными.

Ранее поставлявшееся в составе Delphi автономное средство ReportSmith с Delphi версии 3 более не поставляется.

• Local InterBase Server

Локальная однопользовательская версия SQL-сервера Borland InterBase. Поддерживает 2 активных соединения клиентов с сервером. Используется в основном для создания БД, отладки клиентских приложений, которые будут работать с Удаленными БД. В дальнейшем, после отладки, БД переносятся на действительно удаленный сервер, а приложение клиентского места перенастраивается для работы с удаленной БД. Данная перенастройка обычно не требует больших трудозатрат.

• InterBase Server for Windows 95

4-х-пользовательская версия SQL-сервера Borland InterBase, которая может устанавливаться на компьютерах, работающих под управлением Windows 95. Используется для тех же цедей< что и Local InterBase Server, однако на InterBase for Windows 95 можно производить отладку в многопользовательском режиме, что важно для проверки корректности изменений, одновременно вносимых пользователями в БД при параллельной работе с ней.

На рис. 3.2. показаны основные средства в составе интегрированной среды Delphi для работы с БД

Интегрированная среда разработчика Delphi (IDE, Integrated Development Environment)



Локальные базы данных и архитектура "файл-сервер"


При работе с локальными базами данных сами БД расположены на том же компьютере, что и приложения, осуществляющие доступ к ним. Работа с БД происходит в однопользовательском режиме. BDE распложена на компьютере пользователя. Приложение ответственно за поддержание целостности БД и за выполнение запросов к БД. Общая схема однопользовательской архитектуры

показана на рис. 3.4.

При работе в архитектуре "файл-сервер" БД и приложение расположены на файловом сервере сети (например, Novell NetWare). Возможна многопользовательская работа с одной и той же БД, когда каждый пользователь со своего компьютера запускает приложение, расположенное на сетевом сервере. Тогда на компьютере пользователя запускается копия приложения. По каждому запросу к БД из приложения данные из таблиц БД перегоняются на компьютер пользователя, независимо от того, сколько реально нужно данных для выполнения запроса. После этого выполняется запрос.

Каждый пользователь имеет на своем компьютере локальную копию данных, время от времени обновляемых из реальной БД, расположенной на сетевом сервере. При этом изменения, которые каждый пользователь вносит в БД, могут быть до определенного момента неизвестны другим пользователям, что делает актуальной задачу систематического обновления данных на компьютере пользователя из реальной БД. Другой актуальной задачей является блокирование записей, которые изменяются одним из пользователей; это необходимо для того, чтобы в это время другой пользователь не внес изменений в те же данные.

В архитектуре "файл-сервер" вся тяжесть выполнения запросов к БД и управления целостностью БД ложится на приложение пользователя. БД на сервере является пассивным источником данных. Общая схема архитектуры "файл-сервер" показана на рис. 3.5.

Кардинальных различий с точки зрения архитектуры между однопользовательской архитектурой и архитектурой "файл-сервер" нет. И в том, и в ином случае в качестве СУБД применяются так называемые "персональные" (или "локальные") СУБД, такие как Paradox, dBase и пр. Сама база данных в этом случае представляет собой набор таблиц, индексных файлов, файлов полей комментариев (мемо-полей) и пр., хранящихся в одном каталоге на диске в виде отдельных файлов.



Удаленные базы данных и архитектура "клиент-сервер"


Архитектура "файл-сервер" неэффективна по крайней мере в двух отношениях:

1. При выполнении запроса к базе данных, расположенной на файловом сервере, в действительности происходит запрос к локальной копии данных на компьютере пользователя. Поэтому перед выполнением запроса данные в локальной копии обновляются из реальной БД. Данные обновляются в полном объеме. Так, если таблица БД состоит из 1000 записей, а для выполнения запроса (например, выдать сумму премий за октябрь в отделе Y) реально нужно 10 записей, все равно перегоняются все 1000 записей. Таким образом, не нужно иметь слишком много пользователей и запросов от них, чтобы серьезно "забить" сеть, что, конечно же, не может не сказаться на ее быстродействии.

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

Архитектура "клиент-сервер" разделяет функции приложения пользователя (называемого клиентом) и сервера.

Приложение-клиент формирует запрос к серверу, на котором расположена БД, на структурном языке запросов SQL (Structured Query Languague), являющемся промышленным стандартом в мире реляционных БД. Удаленный сервер принимает запрос и переадресует его SQL-серверу БД. SQL-сервер -специальная программа, управляющая удаленной базой данных. SQL-сервер обеспечивает интерпретацию запроса, его выполнение в базе данных, формирование результата выполнения запроса и выдачу его приложению-клиенту. При этом ресурсы клиентского компьютера не участвуют в физическом выполнении запроса; клиентский компьютер лишь отсылает запрос к серверной БД и получает результат, после чего интерпретирует его необходимым образом и представляет пользователю. Так как клиентскому приложению посылается результат выполнения запроса, по сети "путешествуют" только те данные, которые необходимы клиенту. В итоге снижается нагрузка на сеть. Поскольку выполнение запроса происходит там же, где хранятся данные (на сервере), нет необходимости в пересылке больших пакетов данных. Кроме того, SQL-сервер, если это возможно, оптимизирует полученный запрос таким образом, чтобы он был выполнен в минимальное время с наименьшими накладными расходами.

Все это повышает быстродействие системы и снижает время ожидания результата запроса.

При выполнении запросов сервером существенно повышается степень безопасности данных, поскольку правила целостности данных определяются в базе данных на сервере и являются едиными для всех приложений, использующих эту БД. Таким образом, исключается возможность определения противоречивых правил поддержания целостности. Мощный аппарат транзакций, поддерживаемый SQL-серверами, позволяет исключить одновременное изменение одних и тех желанных различными пользователями и предоставляет возможность откатов к первоначальным значениям при внесении в БД изменений, закончившихся аварийно.

Таким образом, функциями приложения-клиента являются:

1. посылка к серверу запросов;

2. интерпретация результатов запросов, полученных от сервера, и представление их пользователю в требуемой форме;

3. реализация интерфейса пользователя.

SQL-сервер - это программа, расположенная на компьютере сетевого сервера. SQL-сервер должен быть загружен на момент принятия запроса от клиента. Функциями сервера БД являются:

1. прием запросов от приложений-клиентов, интерпретация запросов, выполнение запросов в БД, отправка результата выполнения запроса приложению-клиенту;

2. управление целостностью БД, обеспечение системы безопасности, блокировка неверных действий приложений-клиентов;

3. хранение бизнес-правил, часто используемых запросов в уже интерпретированном виде;

4. обеспечение одновременной безопасной и отказоустойчивой многопользовательской работы с одними и теми же данными.

В архитектуре "клиент-сервер" используются так называемые "удаленные" (или "промышленные") СУБД. Промышленными они называются из-за того, что именно СУБД этого класса могут обеспечить работу информационных систем масштаба среднего и крупного предприятия, организации, банка. Локальные СУБД предназначены для однопользовательской работы или для обеспечения работы информационных систем, рассчитанных на небольшие группы пользователей.

К разрядку промышленных СУБД принадлежат Oracle, Gupta, Informix, Sybase, MS SQL Server, DB2, InterBase и ряд других.

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

Кроме этого, существует отдельная категория сотрудников, называемых администраторами баз данных. Как правило, это администраторы сервера, разработчики БД или пользователи, имеющие привилегии на создание, изменение, настройку оптимальных параметров отдельных серверных БД. Администраторы БД также отвечают за предоставление прав на разноуровневый доступ к сопровождаемым ими БД для других пользователей.

Использование архитектуры "клиент-сервер":

1. резко уменьшает сетевой график;

2. понижает сложность приложений-клиентов (поскольку тем уже нет 1 необходимости обеспечивать целостность и безопасность БД и следить за параметрами многопользовательской работы с БД);

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

4. повышает надежность БД, ее целостность, безопасность и секретность.



Многозвенная архитектура "клиент-сервер"


Развитие идеи архитектуры "клиент-сервер" привело к появлению многозвенной архитектуры доступа к базам данным (в литературе ее также называют трехзвенноя архитектурой, N-tier или multi-tier архитектурой).

Архитектура "клиент-сервер" является двухзвенной. Первым звеном является приложение клиента, вторым - сервер БД и сама БД.

В трехзвенной архитектуре наборы данных, бывшие ранее "собственностью" клиентских приложений, выделяются в отдельное звено, называемое сервером приложений (рис. 3.7).

Выше говорилось о модулях данных (Data Module). По существу, это компонент Delphi контейнерного типа, подобно компоненту формы TForm, хранящий в себе другие компоненты. Такими компонентами для Data Module могут служить только невизуальные компоненты БД - компоненты типа "набор данных" (TTable, TQuery, TStoredProc) и компоненты типа TDataSource, являющиеся промежуточными компонентами, связывающими между собой компоненты типа "набор данных" и визуальные компоненты БД.

Использование контейнеров Data Module имеет то преимущество, что компоненты типа "набор данных", единожды размещенные в Data Module, могут использоваться во всех формах приложения. При этом компоненты типа "набор данных", размещенные в Data Module, обладают единым поведением для всего приложения. Это особенно важно при реализации бизнес-правил, хранящихся в приложениях клиента.

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

Итак, модули данных в трехзвенной архитектуре "клиент-сервер" выделяются в отдельный "сервер приложений". Совместно с ним располагается BDE. Теперь, при изменении бизнес-правил нет необходимости изменять приложения клиентов и обновлять их у всех пользователей-клиентов, как это было ранее, когда часть бизнес-правил хранилась в приложении клиента.

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

Взаимодействие клиентского приложения (в многозвенном приложении называемого "тонким клиентом", thin client) с сервером приложений осуществляется при помощи так называемых "брокеров данных". Это появившиеся в Delphi 3 компоненты TRemoteServer (располагающийся в приложении тонкого клиента) и TProvider (расположенный на сервере приложений).



Архитектуры баз данных


Общий состав средств, необходимых для работы готового приложения с БД, показан на рис. 3.3. Согласно этой общей схеме, мы имеем цепочку Приложение —> BDE —> базы данных

В структуре приложения имеется цепочка Невизуальные компоненты —> Визуальные компоненты

Более подробно взаимосвязи между компонентами приложения рассматриваются ниже. Местоположение BDE и самих баз данных в этой цепочке не отражены.

Между тем, местоположение BDE и баз данных зависит от используемой архитектуры. Имеется четыре разновидности архитектур баз данных:

• локальные базы данных;

• архитектура "файл-сервер";

• архитектура "клиент-сервер";

• многозвенная (трехзвенная N-tier или multi-tier) архитектура.

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



Общая структура приложения, работающего с базами данных


На рис. 3.8 показана общая структура приложения, работающего с базами данных.

Как видно из рисунка, при рассмотрении структуры приложения работающего с БД, вполне можно абстрагироваться от расположения BDE и самой базы данных. Приложение состоит из невизуальных и визуальных компонентов работы с БД, компонентов для выдачи отчетов (которые представляют разновидность визуальных компонентов), а также модулей

данных.

Невизуальные компоненты имеют прямой выход на BDE, которая, в свою очередь, контактирует с БД.

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

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

Приложение состоит из одной или нескольких форм. Каждая форма может:

• хранить и использовать свои "собственные" невизуальные компоненты;

• использовать невизуальные компоненты, хранящиеся в одном или нескольких модулях данных;

• использовать невизуальные компоненты, хранящиеся и используемые в

других формах.

Каждая форма может воспользоваться только "собственными" визуальными компонентами, поскольку визуальные компоненты выполняют интерфейсные функции и при деактивизации формы теряют свою видимость на экране.



Обзор не визуальных компонентов для работы с базами данных


TSession

Содержит информацию о текущем сеансе работы с БД; позволяет определить список доступных и активных БД, открывать, отыскивать и закрывать БД, управлять параметрами.

TDataBase

Активно используется при работе в архитектуре "клиент-сервер". Позволяет осуществлять соединение с удаленной БД и управлять параметрами соединения, получать информацию о БД, получать информацию об открытых НД и о доступных таблицах БД.

TDataSource

Служит промежуточным звеном в цепочке "Набор данных - TDataSource - Визуальные компоненты для работы с данными". Позволяет устанавливать некоторые параметры НД, устанавливать состояние НД, отслеживать изменения в НД.

TDataSet TBDEDataSet TDBDataSet

Явно в приложениях не используются, однако ценны тем, что являются предками активно используемых в приложениях компонентов типа "набор данных" (TTable, TQuery и TstoredProc). Определяют ряд свойств и методов, наследуемых и частично переопределяемых компонентами TTable, TQuery и TStoredProc. TDataSet определяет свойства и методы для работы с БД, независимые от машины баз данных. Многие из них являются абстрактными или виртуальными. TBDEDataSet, определяет ряд свойств и методов, зависящих от используемой машины баз данных. TDBDataSet дополнительно вводит ряд свойств.

TTable

Реализует набор данных, источником данных для которого является одна таблица БД. Содержит множество методов, свойств и событий, посредством которых можно выполнять над НД богатый спектр операций. Многие из них расширяют множество свойств, методов и событий, определенных в предках Ttable - компонентах TDataSet и TBDEDataSet.

TQuery

Реализует набор данных, источником данных для которого являются одна или несколько таблиц БД. Структура записи НД, состав НД определяются SQL-запросом (оператор SELECT). Кроме выдачи НД, используется для групповых операций обновления, добавления или удаления в ТБД, а также может выполнять любые действия, Предусмотренные реализацией языка SQL для тон СУБД, с которой работает TQuery. Для типов данных так называемых "персональных" СУБД позволяет реализовывать "локальный" вариант SQL. При помощи TQuery можно реализовывать как статические, так и динамические (изменяющиеся в процессе выполнения приложения) SQL-запросы.

TStoredProc

Используется в архитектуре "клиент-сервер" для доступа к хранимым процедурам, расположенным на удаленной БД. Хранимые процедуры кодируются на особом процедурном языке, хранят, как правило, часто употребляемые запросы к БД и могут разделяться между различными приложениями. Компонент TStoredProc наряду с компонентами TTable и TQuery является набором данных, поскольку может возвращать множество записей из одной или нескольких физических таблиц БД.

TIndexDefs

Позволяет получить информацию об индексах, определенных для данной ТБД, и об индексных полях для текущего индекса; реализует поиск индекса по группе индексных полей.

TFieldDefs

Позволяет получить информацию о полях, определенных в составе записей данной ТБД.

TField

Реализует поле НД. Помимо полей, физически определенных в ТБД и включенных в состав конкретного НД, компонент TField создается для каждого вычисляемого поля или поля, возвращающего значение из другого НД (lookup), а также для результатов вычисления выражений и агрегатных функций в SQL-запросах. Предоставляет набор свойств, методов и событий, посредством которых можно управлять поведением поля. Собственно TField есть родительский класс для дочерних компонентов, реализующих поля конкретных типов (TStringField, TIntegerField, и т.д.). Tfield определяет свойства, методы и события, которые по праву наследования доступны во всех дочерних классах полей.

TBatchMove

Позволяет осуществлять копирование и перенесение записей из одних НД в другие.

TCUentDataSet

Компонент типа "набор данных" для приложения тонкого клиента. Используется в многозвенной архитектуре доступа к БД.

TRemoteServer

Брокер данных, расположенный в приложении тонкого клиента (многозвенная архитектура). Используется для соединения приложения тонкого клиента с сервером приложений.

TProvider

Брокер данных, расположенный на сервере приложений (многозвенная архитектура). Используется для соединения сервера приложения с приложением тонкого клиента.

TDecisionCube

Осуществляет многомерное представление данных для систем принятия решений.

TDecisionQuery

Вариант TQuery для работы с TDecisionCube при использовании систем принятия решений.

TDecisionSource

Разновидность компонента TdataSource для работы с многомерными данными в системах принятия решений.



Обзор визуальных компонентов для работы с базами данных


TDBText

Показывает "только для чтения" значение поля текущей записи НД.

TDBEdit

Обеспечивает просмотр и изменение значения поля текущей записи НД. Поля - любого типа, кроме полей комментариев и BLOB.

TDBCheckBox

Обеспечивает просмотр и изменение значения поля типа Boolean текущей записи НД.

TDBRadioGroup

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

TDBMemo

Позволяет просматривать и корректировать значение мемо-поля (поля комментария) в режиме текстового редактора.

TDBRichEdit

Имеет то же назначение, что и TDBMemo, но позволяет работать с текстом формата RTF, включающим разные шрифты, графику и пр.

TDBImage

Позволяет просматривать графические поля, заносить в них содержимое.

TDBListBox

Применяется, когда нужно выбрать значение поля из предустановленного списка значений; значения показываются в виде строк в списке фиксированного размера. Содержимое списка определяется свойством Items.

TDBComboBox

Применяется для тех же целей, что и TDBListBox, но список "выпадающий".

TDBLookupListBox

Применяется для выбора значения поля из списка значений, который формируется из определенного столбца другого набора данных. Высота списка фиксирована

TDBLookupCombo Box

Применяется для тех же целей, что и TDBLookupListBox, но список - комбинированного вида ("выпадающий").

TDBGrid

Показывает содержимое полей НД в "табличном" виде, когда записям соответствуют строки, полям - столбцы

TDBCtrlGrid

"Продвинутая" версия компонента TDBGrid, позволяющая, в отличие от последнего, показывать содержимое одной записи НД в нескольких строках

TColumn

Столбец компонента TDBGrid, обладающий свойствами и методами, которые позволяют управлять его поведением

TQuickRep

Компонент TQuickRep и связанная с ним группа компонентов позволяет разрабатывать формы отчетов.

TDBNavigator

Позволяет осуществлять навигацию по записям НД, переводить НД в состояния вставки, изменения, добавления записи, запоминать изменения

TDBChart

Реализует графическое представление данных, хранящихся в компонентах типа "набор данных".

TDecisionGraph

Представляет в графическом виде многомерные данные при работе с системами принятия решений.

TDecisionPivot

Реализует двумерную проекцию многомерных данных при работе с системами принятия решений.

TDecisionGrid

Разновидность компонента TDBGrid для табличного представления многомерных данных при работе с системами принятия решений.



Иерархия классов важнейших невизуальных компонентов для представления данных и доступа к ним


TComponent

TSession

TDatabase

TDataSource

TDataSet

TBDEDataSet

TDBDataSet

TTable

TQuery

TStoredProc

TClientDataSet

TField

TBIobField

TGraphicField

TMemoField

TbooleanField

TBooleanField

TBmaryField

TBytesField

TVarBytesField

TDateTimeField

TDateField

TTimeField

TNumericField

TBCDField

TFloatField

TCurrencyField

TIntegerField

TAutoIncField

TSmallIntField

TWordField

TStringField

Приведенная здесь иерархия показывает, что свойства, методы и события, объявленные у компонентов-предков, по праву наследования доступны и у их компонентов-потомков.

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

Другим примером может служить TDataSet: многие его свойства, методы и события по праву наследования доступны и у его потомков - компонентов TTable и TQuery.

О наследовании компонентами-потомками свойств, методов и событий своих родителей следует помнить постоянно.



Функциональная иерархия компонентов Delphi для работы с базами данных


Если иерархия классов компонентов, приведенная в предыдущем подразделе, призвана показать, кто является чьим потомком и, следовательно, кто может использовать свойства, методы и события родителя, то приводимая на рис.4.1 функциональная иерархия не зависит от "классовой" структуры.

В функциональной иерархии показывается, какие компоненты являются свойствами других компонентов и, соответственно, к каким компонентам, связанным с текущим, мы можем получить доступ

Приведенная схема призвана показать следующее.

Используя неявно создаваемый или явно созданный компонент TSession (подробности в соответствующем разделе), можно определить, какие базы данных в текущий момент активны для приложения (свойство Databases).

Используя компонент TDatabase, можно определить, какие наборы данных используются приложением (компонент TDataSet).

Используя компонент TDataSet, можно:

• для НД, связанных с компонентом TTable:

• узнать, какие индексы определены для таблицы БД, ассоциированной с этим набором данных (компонент TIndexDef);

• для каждого индекса получить информацию об индексных полях и перейти к использованию свойств и методов отдельного индексного поля;

• получить информацию обо всех полях, определенных в структуре ТБД, ассоциированной с данным компонентом TTable (свойство FieldDefs.Items);

• для всех наборов данных (компоненты TTable, TQuery, TStoredProc ) -получить информацию обо всех активных полях набора данных и получить доступ к свойствам и методам каждого активного поля. Таким образом, информация о структурах данных различных уровней носит в приложении Delphi сквозной характер. Взяв за стартовую точку текущую сессию (сеанс) приложения по работе с БД, можно "спуститься" к отдельному полю какого-либо набора данных.

Более подробно о работе каждого компонента и о связи его с другими -визуальными и невизуальными компонентами для работы с данными - будет рассказано в соответствующих разделах.



Как связаны друг с другом компоненты для работы с базами данных


Визуальные и невизуальные компоненты связываются друг с другом при помощи свойств. Значения этих свойств обычно устанавливаются на этапе разработки приложения, но могут устанавливаться и во время выполнения приложения. На рис. 4.2 показано, через какие свойства различные компоненты связаны друг с другом.

Первым уровнем являются псевдонимы BDE, устанавливаемые при помощи ВDE Administrator. На псевдоним ссылается компонент типа "набор данных" (показанные на рисунке компоненты TTable и Tquery, не показанный компонент TStoredProc, применяемый преимущественно в архитектуре "клиент-сервер"). Имя псевдонима БД записывается как значение свойства DataBaseName этих компонентов.

При работе в архитектуре "клиент-сервер" псевдоним БД часто записывается в свойство AliasName компонента TDatabase, отвечающего за связь с удаленной БД. База данных получает новый псевдоним (свойство DataBaseName компонента TDatabase). В этом случае компоненты типа "набор данных" в свойстве DataBaseName хранят значение из свойства DataBaseName компонента TDatabase.

Компонент TTable работает с записями одной физической таблицы БД. Поэтому свойство TableName этого компонента хранит имя этой таблицы БД.

Компонент TQuery в общем случае возвращает набор данных, записи которого получены в результате выполнения запроса к одной или нескольким таблицам БД. Имена таблиц и условия выборки из них записей устанавливаются в запросе (SQL-оператор SELECT), который хранится в свойстве SQL компонента TQuery.

Имя любого компонента типа "набор данных" хранится в его свойстве Name. Свойство Active указывает, активен ли (открыт, готов для доступа к данным) соответствующий набор данных (значение True) или не активен (значение False). Открытие НД производится на этапе разработки приложения и во время выполнения установкой свойства Active в значение True, а также во время выполнения - при помощи метода Open этого набора данных.

Для связи визуальных и невизуальных компонентов для работы с данными используется компонент "промежуточного уровня", TDataSource (источник данных). Его свойство DataSet содержит имя соответствующего компонента типа "набор данных".

Визуальные компоненты разделяются на работающие с множеством записей набора данных (например, TDBGrid) и с отдельным полем (TDBEdit и другие). Соответственно, компоненты, работающие с множеством записей, ссылаются в своем свойстве DataSource только на имя компонента TDataSource;

компоненты, работающие с конкретным полем, кроме этого ссылаются на имя поля НД (свойство FieldName). Список доступных полей набора данных хранится в свойстве Fields соответствующего компонента типа "набор данных".



Назначение BDE Administrator


В Delphi для доступа к базам данных из приложения, как известно, используется цепочка "Приложение -> BDE -> База данных". Это означает, что при любом обращении к БД из приложения реально адресуется BDE (напомним, это аббревиатура Borland Database Engine, машины баз данных фирмы Borland). BDE, используя собственные функции, связывается непосредственно с базой данных. Действия, осуществляемые при этом BDE, мы здесь обсуждать не будем, поскольку эта тема отдельного рассмотрения.

Для работы с конкретной базой данных BDE, во-первых, должна знать:

• где БД физически расположена;

• параметры этой БД,

• общие параметры драйвера БД того типа, к которому принадлежит обрабатываемая БД;

• общие системные установки.

Параметры драйвера БД определяют параметры конкретной БД, значения которых не указаны.

Системные установки являются общими для всех драйверов. Замечание. Те,-кто работал с Delphi версий 1 и 2, будут поначалу неприятно удивлены, не обнаружив в 3-ей версии BDE Configuration Utility. Именно ее функции и выполняет в Delphi 3 утилита BDE Administrator Несомненно, что Вы найдете в ней много общего с BDE Configuration Utility.



Создание псевдонима БД


Параметры БД и ее местоположение определяются псевдонимом БД. Псевдоним - это некоторое имя (псевдоним БД). Именно этот псевдоним и используют при логическом обращении к БД компоненты типа "набор данных" приложения Delphi, например TTable и TQuery. BDE считывает параметры, поставленные в соответствие данному псевдониму, что во многом определяет ее дальнейшие действия по физической работе с БД.

Псевдонимы баз данных определяются в утилите BDE Administrator. Для того, чтобы определить псевдоним, необходимо:

1. Выбрать элемент меню Object \ New;

2. Выбрать в появившемся окне имя драйвера базы данных (STANDARD для Paradox и dBase, MSACCESS для Microsoft Access, ORACLE INTRBASE, SYBASE, MSSQL, INFORMIX, DB2 соответственно для баз данных Oracle, InterBase, Sybase, MS SQL Server, Informix, DB2 и, если установлен, драйвер ODBC);

4. Ввести имя псевдонима в левом окне;

5. Определить необходимые параметры псевдонима в правом окне (рис. 5.1);

6. Щелкнуть по псевдониму правой кнопкой мыши и выбрать во всплывающем меню элемент Apply для подтверждения или Cancel для отказа.

Поскольку в настоящей книге основной упор делается на использование "родных" баз данных Borland (Paradox и InterBase), опишем далее параметры драйверов этих баз данных. Для получения информации о создании псевдонимов БД иных типов обратитесь к системной документации и встроенной системе помощи.



Параметры баз данных типа STANDARD


Этот тип используется для доступа к локальным БД (Paradox, dBase). Таблицы, индексы, мемо-поля локальных БД хранятся раздельно друг от друга, каждый в своем файле. База данных в этом случае - группа таких файлов, собранных в одном каталоге на диске. Псевдоним БД указывает на такой каталог.

При определении псевдонима БД указываются следующие параметры:

DRIVER -

определяет тип СУБД (PARADOX, DBASE или ASCIIDRV для довольно редкого случая использования в качестве таблиц БД колумнированных, т.е. разбитых на колонки, текстовых файлов);

ENABLE BCD -

указывает на необходимость для BDE переводить целые и десятичные значения полей в значения BCD (binary coded decimal, двоично-десятичные кодированные значения). BCD позволяет устранить ошибки округления, имеющие место, например, когда результат выражения (1/3)*3 равен 0.99998 или 1.000001, что имеет место для операций над целыми и десятичными значениями. TRUE заставляет BDE преобразовывать целые и десятичные значения в BCD-формат, PATH - указывает путь на диске к каталогу, в котором расположены файлы БД.

Установки параметров драйвера PARADOX


Параметры, присущие всем БД того или иного типа, устанавливаются для драйверов БД. Затем они применяются к псевдониму каждой БД того же типа. Некоторые параметры могут быть переопределены для конкретного псевдонима, а некоторые - нет.

Установка параметров драйверов производится после выбора закладки Configuration и раскрытия дерева до ветви Drivers \ Native \ Имя драйвера (рис.5 2). В ветви Drivers \ ODBC производятся установки драйвера ODBC.

Параметры драйвера PARADOX:

VERSION -

Внутренняя версия драйвера Paradox;

TYPE -

Тип сервера - SERVER (SQL-сервер) или FILE (однопользовательские БД, файл-серверные БД).

NET DIR -

Каталог, в котором расположен сетевой управляющий файл PDOXUSRS.NET. Для работы с файлами Paradox в сети необходимо установить параметр NET DIR , предварительно расположив фат PDOXUSRS.NET в указанном каталоге.

LANGDRIVER -

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

Pdox ANSI Cyrillic.

Для этого драйвера без ошибок работают символьные функции для перевода строчных букв в заглавные и обратно Ansi UpperCa “ и AnsiLowerCase.

LEVEL -

Тип временных таблиц Paradox (уровень версии)'

7 - 32-битные таблицы Paradox для Windows;

5 - Таблицы Paradox 5.0;

4 - Стандартный формат таблиц (Paradox 4.0);

3 - Формат таблиц, совместимый с Paradox 3.5 и более ранними версиями.

По умолчанию принят 4 уровень. Уровни 4 и 5 позволяют использовать blob-поля, вторичные индексы, строгие ограничения ссылочной целостности.

7 уровень следует использовать в случае применения поддержки улучшенной индексации таблиц

BLOCK SIZE -

Определяет размер блока на диске при хранении записей таблиц Paradox. По умолчанию 2048. Размер блока кратен 1024 байтам Возможные значения для уровней 5 и 7. 1024,2048,4096, 16384 или 32768. Для уровней 3 и 4 - 1024, 2048 или 4096.

• FILL FACTOR -

Процент заполнения блока на диске, когда Paradox начнет выделение нового блока Значение в диапазоне 1 .100 По умоччанию 95. Малые размеры блока улучшают быстродействие индексов, но увеличивают их размер; большие размеры блока уменьшают размер индекса, но ухудшают их быстродействие.

• STRICTINTEGRTY -

Указывает, могут ли изменяться значения в таблицах Paradox в приложениях, не поддерживающие ссылочную целостность (к примеру, Paradox 4.0). Значение TRUE запрещает изменять таблицы Paradox 4.0, связанные ссылочной целостностью; FALSE разрешает такие изменения с риском нарушения ссылочной целостности. По умолчанию TRUE.

Установки параметров драйвера INTERBASE


VERSION - неизменяемый параметр. Содержит версию драйвера InterBase.

TYPE -

значение SERVER указывает, что работа с БД происходит с использованием SQL-сервера.

DLL -

неизменяемый параметр, для внутреннего использования. Содержит имя библиотеки динамического вызова (DLL, dynamic link library) для работы с 16-разрядными вызовами.

DLL32 -

неизменяемый параметр, для внутреннего использования Содержит имя библиотеки динамического вызова (DLL, dynamic link library) для работы с 32-разрядными вызовами.

TRACE MODE -

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

BATCH COUNT -

число записей, изменяемых в рамках неявной транзакции. Перед изменением записей автоматически стартует транзакция на сервере. После изменения этого числа записей транзакция на сервере автоматически подтверждается. Более подробно о явном и неявном старте и подтверждении транзакций см. раздел книги, посвященный управлению транзакциями. Использование BATCH COUNT дает возможность изменить число записей в пакете обновлений для каждой подтвержденной транзакции, если размер подобного пакета на сервере недостаточно велик. По умолчанию - число записей, умещающихся в пакете длиной 32 К.

ENABLE BCD -

Указывает на необходимость для BDE переводить целые и десятичные значения полей в значения BCD.

ENABLE SCHEMA CACHE -

при значении TRUE позволяет хранить сведения о структуре, удаленной БД на клиентском компьютере в каталоге, определяемом параметром SCHEMA CACHE DIR. Хранение структуры БД хорошо тем, что в этом случае BDE не нужно всякий раз считывать данную информацию из удаленной БД, что экономит время и ресурсы. Однако хранение структуры БД возможно лишь для БД, чья структура (состав таблиц, столбцов, индексов и др.) не изменяется во времени. В противном случае выдается ошибка.

SCHEMA CACHE TIME -

в случае хранения сведений о структуре БД параметр указывает, с какой периодичностью BDE обновляет сведения о структуре БД. Значения:

• 0 - хранение схемы БД не используется;

• 1 (по умолчанию) - после закрытия БД в приложении (т.е. после разрыва соединения с БД);

• число в диапазоне 1..2 147 483 647 - число секунд для обновления

сведений о структуре БД.

LANGDRIVER -

Языковый драйвер, используемый для кодировки символьных полей и определяющий также порядок сортировки символьных значений. Для русскоязычных приложений рекомендуется Pdox ANSI Cyrillic. Для этого драйвера без ошибок работают символьные функции преобразования строчных/заглавных букв AnsiUpperCase и AnsiLowerCase. Pdox ANSI Cyrillic совместим с кодировкой символов InterBase WIN 1251 и порядком сортировки символов (collation order) PXW_CYRL. Эти значения указываются в БД в атрибутах: DEFAULT CHARACTER SET для баз данных, CHARACTER SET и COLLATE для доменов и столбцов.

МАХ ROWS -

указывает максимальное число записей, которые драйвер пытается считать из удаленной БД при посылке каждого SQL-запроса к серверу, с учетом запросов на чтение структуры БД и проверки соответствия значений столбцов накладываемым на них ограничениям. Используется для предотвращения безграничного расхода системных ресурсов, например, при выдаче оператора "SELECT *..." для большой по объему таблицы БД. Малое значение МАХ ROWS может привести к тому, что таблица БД не сможет быть открыта, поскольку запрос чтения структуры таблицы может возвратить больше записей, чем указано в МАХ ROWS. Однако МАХ ROWS никак не воздействует на не-обновляемые запросы. По умолчанию принято (-1), что означает отсутствие лимита на количество считываемых строк.

В случае, если количество возвращаемых строк больше установленного лимита, выдается ошибка DBIERR_ROWFETCHLIMIT. Поэтому следует перенастраивать такие приложения для использования DBIERR.ROWFETCHLIMIT вместо DBIERR_EOF (конец данных). OPEN MODE - устанавливает режим чтения-записи данных из (в) БД (значение READ/WRITE, по умолчанию) и режим "только для чтения" (READ ONLY).

SERVER

NAME - для удаленных БД содержит имя сетевого сервера и путь к БД на сетевом сервере. Вид указания имени сервера и пути зависит

от используемого сетевого протокола. Для протокола TCP/IP при расположении БД на сервере, который работает под управлением Windows NT/95, указание пути к удаленной БД производится в формате ИмяСервера:Путь\ИмяБД.gdb, например:

mdl:c:\ptoject\bd\mon.gdb

При этом должны быть соответствующим образом настроены файлы HOSTS и SERVICES на компьютере, имеющем доступ к удаленной БД (более подробно см. раздел, посвященный введению в технологию "клиент-сервер", где, в частности, обсуждаются вопросы связи БД InterBase и клиентских приложений, созданных с помощью Delphi). SQLPASSTHRU MODE - важнейший в рамках технологии "клиент-сервер" режим, определяющий, каким образом происходит взаимодействие BDE с сервером на уровне транзакций приложения клиента.

Значение параметра определяет, может ли BDE передавать серверу собственные команды для управления запросами, или нет. В последнем случае используется Passthrough SQL - операторы SQL, выполняемые при помощи компонента TQuery клиентского приложения. Также данный параметр определяет режимы использования неявного старта и подтверждения транзакций. Более подробно с данной проблематикой можно ознакомиться в разделе книги, посвященном управлению транзакциями.

Параметр SQLPASSTHRU MODE может принимать следующие значения:

• SHARED AUTOCOMMIT - PassthroughSQL и команды BDE используют одно и то же соединение с удаленной БД, реализуемое в приложении через один компонент TDatabase. В том случае, если в приложении транзакция явно не реализуется методом TDatabase-StartTransaction, происходит неявный старт транзакции и ее автоматическое подтверждение.

• SHARED NOAUTOCOMMIT -

Passthrough SQL и команды BDE используют одно и то же соединение с удаленной БД, неявные транзакции стартуют аналогично режиму SHARED AUTOCOMMIT, однако их неявного подтверждения не происходит и это нужно делать явно. Поведение Passthrough SQL в этом случае зависит от сервера.

• NOT SHARED -

Passthrough SQL и команды BDE не могут использовать одно и то же соединение с удаленной БД. Обновляемые запросы на SQL не поддерживаются псевдонимами БД, для которых установлен режим NOT SHARED.

SHARED AUTOCOMMIT и SHARED NOAUTOCOMMIT не поддерживают всех операторов Passthrough SQL. В режимах SHARED AUTOCOMMIT или SHARED NOAUTOCOMMIT не следует управлять транзакциями при помощи SQL-оператора SET TRANSACTION.

SQLQRYMODE

определяет режим выполнения запросов SQL.

Возможные значения:

• NULL

(по умолчанию) - для доступа как к локальным, так и серверным БД. Запросы вначале посылаются к SQL-серверу. Если тот не в состоянии выполнить запрос, он выполняется локально.

• SERVER -

только серверные БД. Запрос посылается SQL-серверу. Если сервер не может выполнить запрос, локального выполнения не происходит.

• LOCAL -

только локальные БД. Запрос всегда выполняется на клиентской машине, т.е. локально. Заметим, что запрос может быть отвергнут сервером БД, если:

1. имеет место гетерогенный запрос, т.е. запрос к различным БД;

2. запрос состоит более чем из одного SQL-оператора;

3. сервер БД не поддерживает синтаксис операторов, присутствующих в запросе.

• USER

NAME - определяет имя, которое выдается в качестве подсказки имени пользователя при запросе имени пользователя и пароля в момент соединения с БД.

Системные стартовые установки


Выбрав закладку Configuration, раскройте ветвь дерева System \ Init. Здесь могут быть установлены стартовые параметры запуска приложения, работающего с BDE (рис. 5.2). Кроме языкового драйвера, эти установки меняются редко и хотя бы на первых порах при работе с BDE рекомендуется не изменять установки, принятые по умолчанию.

Назначение параметров:

• AUTO ODBC -

TRUE определяет импорт установленных драйверов ODBC. По умолчанию FALSE.

• DATA REPOSITORY -

определяет имя активного словаря данных.

• DEFAULT DRIVER -

Имя драйвера, установленного по умолчанию для локальных БД (для псевдонимов, у которых в параметре TYPE установлено значение FILE и при указании имен файлов не указаны расширения).

LANGDRIVER -

языковый драйвер по умолчанию. Для русскоязычных данных рекомендуется Pdox ANSI Cyrillic.

• LOCAL SHARE -

определяет способность разделять доступ к локальным данным между активными приложениями, как использующими, так и не использующими BDE. Значение TRUE необходимо установить, если доступ к данным будет производиться в приложениях с использованием BDE и в обход BDE. По умолчанию FALSE.

• MAXBUFSIZE

- Максимальный размер буфера (кэша) базы данных, в килобайтах. Значение должно быть кратным 128. По умолчанию 2048. • MINBUFSIZE - Минимальный размер буфера (кэша) базы данных, в килобайтах. Значение должно находиться в диапазоне 32... 65535. По умолчанию 128.

• MAXFILEHANDLES -

максимальное число дескрипторов (handle), используемых BDE. Значение в диапазоне 5...4096. Большое значение увеличивает производительность, но требует большего числа ресурсов Windows. По умолчанию 48.

MEMSIZE -

максимальный размер памяти, доступный BDE для использования. По умолчанию 16MB.

• SHAREDMEMSIZE -

Максимальное количество памяти в килобайтах, которое BDE может использовать для разделения ресурсов. По умолчанию 2048 К. Разделяемыми ресурсами являются дескрипторы (handle), драйверы, табличные объекты и др.. Если их число велико, значение в SHAREDMEMSIZE следует увеличить.

• SHAREDMEMLOCATION -

Содержит адрес менеджера, управляющего разделяемой памятью. Менеджер загружается в память, начиная с указанного адреса. Если этот адрес конфликтует с другими приложениями, его следует изменить. Значения по умолчанию - ЕООО (Windows 95), 7000 (Windows NT).

• SQLQRYMODE

определяет режим выполнения запросов SQL (см. выше).

• VERSION

- неизменяемый параметр, определяющий текущую версию BDE.

Параметры формата даты


SEPARATOR - задает символ для разделения дня, месяца, года в значениях даты, например символ "/" ("31/12/96"). По умолчанию берется символ из системных установок Windows .

• MODE -

задает порядок следования дня (D), месяца (М) и года (Y) в дате. Возможные значения: О (MDY), 1 (DMY), 2 (YMD). По умолчанию берется порядок следования из системных установок Windows.

• FOURDIGITYEAR -

определяет, показывать ли в значении года две (FALSE) или четыре (TRUE) цифры.

• YEARBIASED -

указывает BDE, как преобразовывать значение года, введенное в виде двух цифр (96). Значение TRUE обязывает прибавлять к двузначному году 1900 (введено 96, получено 1996). При значении FALSE этого не происходит (введено 96, получено 0096). По умолчанию TRUE.

• LEADINGZEROM -

указывает (TRUE), что для одноразрядных значений месяца необходимо прибавлять ведущий ноль (например, "16/4/96" преобразовать к виду "16/04/96"). По умолчанию FALSE. • LEADINGZEROD - указывает (TRUE), что для одноразрядных значений дня необходимо прибавлять ведущий ноль (например, "6/12/96" преобразовать к виду "06/12/96"). По умолчанию FALSE.

Параметры формата времени


• TWELVEHOUR - определяет, показывается ли время в двенадцатичасовом формате (TRUE) или в двадцатичетырехчасовом (FALSE). Например, время "10:20 РМ" (12-часовой формат) в 24-часовом формате - "22:20". По умолчанию TRUE.

• AMSTRING -

устанавливает символы, определяющие время до полудня для 12-часового формата. По умолчанию "AM".

• PMSTRING -

устанавливает символы, определяющие время после полудня для 12-часового формата. По умолчанию "РМ".

• SECONDS -

определяет, показываются ли секунды (TRUE) или нет (FALSE). По умолчанию TRUE.

MILSECONDS -

определяет, показываются ли миллисекунды (TRUE) или нет (FALSE). По умолчанию FALSE.

Параметры числового формата


Устанавливают порядок преобразования строковых значении в числовой формат.

• DECIMALSEPARATOR -

устанавливает символ, отделяющий целую часть числа от дробной. По умолчанию берется значение, установленное в Windows.

THOUSANDSEPARATOR - устанавливает символ, служащий разделителем тысяч в целой части числа (например, 7,654,321.00). По умолчанию берется значение, установленное в Windows.

DECIMALDIGITS - указывает число разрядов в дробной части числа. По умолчанию 2.

LEADINGZERON

- указывает, имеют ли числа в диапазоне 1..-1 ноль в целой части (TRUE) или нет (FALSE). Например, 0.22 и .22. По умолчанию TRUE.

Установки форматов


Ветвь System \ Formats используется для установки форматов даты (Date}, времени (Time} и числовых значений (Number}.



Сохранение конфигурации в отдельном файле


Текущая конфигурация со значениями псевдонимов, драйверов и стартовых настроек может быть сохранена в файле. Для этого нужно выбрать раздел меню Object | Save As Configuration и указать имя, после чего нажать кнопку Ok. По умолчанию конфигурация записывается в файл Program Files\Borland\ Common Files\BDE\Idapi32.cfg. Этот файл обновляется автоматически после выполнения подтверждения для всех изменений (Object \ Apply) или для каждого изменения (Apply в контекстном меню, вызываемой правой кнопкой мыши).

Файл конфигурации, отличный от принятого по умолчанию, может быть загружен (Object \ Open Configuration).