Как создать таблицу

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

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

Сделать это с помошью менеджера соответствующей базы данных, например таблицу для Paradox создать в Paradox’e

С помощью Database Desktop — утилита , постовляемая с BDE и большинством борландовских продуктов. Я не думаю что вы встретите проблемы при создании таблицы — там всё очень просто.

Из программы.

Здесь 2 варианта, вариант первый, использовать метод CreateTable у таблицы, вот пример из справки по Дельфи как Борланд предлагает это делать:

with Table1 do

begin

Active := False;

DatabaseName := ‘DBDEMOS’;

TableType := ttParadox;

TableName := ‘CustInfo’;

{ Don’t overwrite an existing table }

if not Table1.Exists then

begin

{ The Table component must not be active }

{ First, describe the type of table and give }

{ it a name }

{ Next, describe the fields in the table }

with FieldDefs do

begin

Clear;

with AddFieldDef do

begin

Name := ‘Field1’;

DataType := ftInteger;

Required := True;

end;

with AddFieldDef do

begin

Name := ‘Field2’;

DataType := ftString;

Size := 30;

end;

end;

{ Next, describe any indexes }

with IndexDefs do

begin

Clear;

{ The 1st index has no name because it is

{ a Paradox primary key }

with AddIndexDef do

begin

Name := »;

Fields := ‘Field1’;

Options := [ixPrimary];

end;

with AddIndexDef do

begin

Name := ‘Fld2Indx’;

Fields := ‘Field2’;

Options := [ixCaseInsensitive];

end;

end;

{ Call the CreateTable method to create the table }

CreateTable;

end;

end;

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

{/codecitation}

Как скопировать структуру таблицы

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Автор: http://www.swissdelphicenter.ch

{

As we know, Paradox Tables consist in a table file and some corresponding index files

there are many way to copy them:

1. Using TBatchMover (at DataAccess Pallete) with Mode : BatCopy

But you can’t copy the tables corresponding index files, TBatchMove just

copies the structure and data.

2. Using FileCopy

But you can’t copy the tables corresponding index files automatically,

you should define each files

.. and many more

The Simple way is:

Put two TTables on your form, name it as tbSource and tbTarget.

Then, put this procedure under implementation area

}

type

TForm1 = class(TForm)

tbSource: TTable;

tbTarget: TTable;

// …

end;

implementation

procedure TForm1.Button1Click(Sender: TObject);

begin

tbSource.TableName := ‘Source.DB’;

// The name of your tables which you want to copy from

tbTarget.TableName := ‘Target.DB’;

// The name of your tables which you will to copy to

// You Can set the tbSource.DataBaseName to an existing path/Alias

// where you store your DB

// You Can set the tbTarget.DataBaseName to an existing path/Alias

// where you want to store the duplicate DB

tbSource.StoreDefs := True;

tbTarget.StoreDefs := True;

tbSource.FieldDefs.Update;

tbSource.IndexDefs.Update;

tbTarget.FieldDefs := tbSource.FieldDefs;

tbTarget.IndexDefs := tbSource.IndexDefs;

tbTarget.CreateTable;

// Actually you can set these code up to only 5 lines 🙂

end;

end.

{/codecitation}

Как очистить таблицу, оставив только структуру

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Замечание:

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

procedure TForm1.Button2Click(Sender: TObject);

begin

{Opens the table in exclusive mode}

try

with Table1 do

begin

Active := False;

Exclusive := True;

Active := True;

try

EmptyTable;

except

ShowMessage(‘Cannot empty database’);

end;

end

except

ShowMessage(‘cannot open table in exclusive mode’);

end

end;

{/codecitation}

Естественные ключи против искусственных ключей

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Переехал программист из России в Северную Америку. Посылает своим родственникам оттуда посылку. Родственники удивилиcь — он обычно только на Новый Год посылки шлет, а тут до Нового Года еще 2 месяца, да и посылка еще в такой коробке, что слона можно поместить. вскрывают коробку, она оказывается изнутри пустая, только на самом дне какая то бумажка лежит. Достают они ее и видят что на бумажке написано: «Test».

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

О сущности проблемы

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

В качестве первичного ключа может использоваться:

Естественный Ключ (ЕК) — набор атрибутов описываемой записью сущности, уникально её идентифицирующий (например, номер паспорта для человека);

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

Есть два мнения:

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

СК должны добавляться в любую таблицу, на которую существуют ссылки (REFERENCES) из других таблиц, и связи между ними должны организовываться только при помощи СК. Разумеется, поиск записи и представление её пользователю по прежнему производятся на основании ЕК.

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

Когда появляются СК

Для понимания места и значения СК рассмотрим этап проектирования, на котором они вводятся в структуру БД, и методику их введения.

Для ясности рассмотрим БД из 2-х отношений — Города (City) и Люди (People) Предполагаем, что город характеризуется Hазванием (Name), все города имеют разные названия, человек характеризуется Фамилией (Family), номером паспорта (Passport) и городом проживания (City). Также полагаем, что каждый человек имеет уникальный номер паспорта. Hа этапе составления инфологической модели БД её структура одинакова и для ЕК и для СК.

CREATE TABLE City(

name VARCHAR(30) not NULL PRIMARY KEY

);

CREATE TABLE People(

Passport CHAR(9) not NULL PRIMARY KEY,

Family VARCHAR(20) not NULL,

City VARCHAR(30) not NULL REFERENCES City(name)

);

Для ЕК все готово. Для СК делаем еще один этап и преобразуем таблицы следующим образом:

CREATE TABLE City(

/*

В разных диалектах языка SQL автоинкрементное поле будет выражено по-разному —

например, через IDENTITY, SEQUENCE или GENERATOR.

Здесь мы используем условное обозначение AUTOINCREMENT.

*/

Id INT not NULL AUTOINCREMENT PRIMARY KEY

name VARCHAR(30) not NULL UNIQUE

);

CREATE TABLE People(

Id INT not NULL AUTOINCREMENT PRIMARY KEY,

Passport CHAR(9) not NULL UNIQUE,

Family VARCHAR(20) not NULL,

CityId INT not NULL REFERENCES City(Id)

);

Обращаю внимание, что:

Все условия, диктуемые предметной областью (уникальность имени города и номера паспорта) продолжают присутствовать в БД, только обеспечиваются не условием PRIMARY KEY, а условием UNIQUE;

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

В общем случае алгоритм добавления СК выглядит следующим образом:

В таблицу добавляется поле INTEGER AUTOINCREMENT;

Оно объявляется PRIMARY KEY;

Старый PRIMARY KEY (ЕК) заменяется на UNIQUE CONSTRAINT ;

Если в таблице есть REFERENCES на другие таблицы, то поля, входящие в REFERENCES, заменяются на одно поле типа INTEGER, составляющее первичный ключ (как People.City заменена на People.CityId).

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

Зачем всё это надо

Возникает резонный вопрос — а зачем? Действительно, вводить в таблицы какие-то поля, что-то заменять, зачем? Итак, что мы получаем, проделав эту «механическую» операцию.

Упрощение сопровождения

Это область, где СК демонстрируют наибольшие преимущества. Поскольку операции связи между таблицами отделены от логики «внутри таблиц» — и то и другое можно менять независимо и не затрагивая остального.

Hапример — выяснилось, что города имеют дублирующиеся названия. Решено ввести в City еще одно поле — Регион (Region) и сделать ПК (City, Region). В случае ЕК — изменяется таблица City, изменяется таблица People — добавляется поле Region (да, да, для всех записей, про размеры молчу), переписываются все запросы, в том числе на клиентах, в которых участвует City, в них добавляются строка AND XXX.Region = City.Region.

Да, чуть не забыл, большинство серверов сильно не любят ALTER TABLE на поля, входящие в PRIMARY KEY и FOREIGN KEY.

В случае СК — добавляется поле в City, изменяется UNIQUE CONSTRAINT. Всё.

Еще пример — в случае СК изменение списка полей в SELECT никогда не заставляет переписывать JOIN. В случае ЕК — добавилось поле, не входящее в ПК связанной таблицы — переписывайте.

Еще пример — поменялся тип данных поля, входящего в ЕК. И опять переделки кучи таблиц, заново оптимизация индексов…

В условиях меняющегося законодательства это достоинство СК само по себе достаточно для их использования.

Уменьшение размера БД

Предположим в нашем примере, что средняя длина названия города — 10 байт. Тогда на каждого человека в среднем будет приходиться 10 байт для хранения ссылки на город (реально несколько больше за счёт служебной информации на VARCHAR и гораздо больше за счёт индекса по People.City, который придётся построить, чтобы REFERENCES работала эффективно). В случае СК — 4 байта. Экономия — минимум 6 байт на человека, приблизительно 10 Мб для г. Hовосибирска. Очевидно, что в большинстве случаев уменьшение размера БД — не самоцель, но это, очевидно, приведет и к росту быстродействия.

Звучали аргументы, что БД может сама оптимизировать хранение ЕК, подставив вместо него в People некую хэш-функцию (фактически создав СК сама). Hо ни один из реально существующих коммерческих серверов БД так не делает, и есть основания полагать, что и не будет делать. Простейшим обоснованием такого мнения является то, что при подобной подстановке банальные операторы ADD CONSTRAINT … FOREIGN KEY или DROP CONSTRAINT … FOREIGN KEY будут приводить к нешуточной перетряске таблиц, с ощутимым изменением всей БД (надо будет физически добавить или удалить (с заменой на хэш-функцию)) все поля, входящие в CONSTRAINT.

Увеличение скорости выборки данных

Вопрос достаточно спорный, однако, исходя из предположений, что:

База данных нормализована;

Записей в таблицах много (десятки тысяч и более);

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

быстродействие системы на СК будет ощутимо выше. И вот почему:

ЕК могут потенциально дать более высокое быстродействие, когда:

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

нет условий WHERE по полям связанных таблиц.

Т.е., в нашем примере это запрос типа:

SELECT Family, City FROM People;

В случае СК этот запрос будет выглядеть как

SELECT P.Family, C.Name

FROM People P INNER JOIN City C ON P.CityId = C.Id;

Казалось бы, ЕК дает более простой запрос с меньшим количеством таблиц, который выполнится быстрее. Hо и тут не всё так просто: размеры таблиц для ЕК — больше (см. выше) и дисковая активность легко съест преимущество, полученное за счёт отсутствия JOIN`а. Ещё сильнее это скажется, если при выборке данных используется их фильтрование (а при сколько-либо существенном объеме таблиц оно используется обязательно). Дело в том, что поиск, как правило, осуществляется по информативным полям типа CHAR, DATETIME и т.п. Поэтому часто бывает быстрее найти в справочной таблице набор значений, ограничивающий возвращаемый запросом результат, а затем путем JOIN`а по быстрому INTEGER-индексу отобрать подходящие записи из большой таблицы. Например:

(ЕК) SELECT Family, City FROM People WHERE City = ‘Иваново’;

будет выполняться в разы медленнее, чем

(CК) SELECT P.Family, C.Name

FROM People P INNER JOIN City C ON P.CityId = C.Id

WHERE C.Name = ‘Иваново’;

В случае ЕК — будет INDEX SCAN большой таблицы People по CHARACTER-индексу. В случае СК — INDEX SCAN меньшей CITY и JOIN по эффективному INTEGER индексу.

А вот если заменить = ‘Иваново’ на LIKE ‘%ваново’, то речь пойдет о торможении ЕК относительно СК на порядок и более.

Аналогично, как только в случае с ЕК понадобится включить в запрос поле из City, не входящее в её первичный ключ — JOIN будет осуществлятся по медленному индексу и быстродействие упадет ощутимо ниже уровня СК. Выводы каждый может делать сам, но пусть он вспомнит, какой процент от общего числа его запросов составляют SELECT * FROM ЕдинственнаяТаблица. У меня — ничтожно малый.

Да, сторонники ЕК любят проводить в качестве достоинства «информативность таблиц», которая в случае ЕК растет. Ещё раз повторю, что максимальной информативностью обладает таблица, содержащая всю БД в виде flat-file. Любое «повышение информативности таблиц» есть увеличение степени дублирования в них информации, что не есть хорошо.

Увеличение скорости обновления данных

INSERT

Hа первый взгляд ЕК быстрее — не надо при INSERT генерировать лишнего поля и проверять его уникальность. В общем-то так оно и есть, хотя это замедление проявляется только при очень высокой интенсивности транзакций. Впрочем и это неочевидно, т.к. некоторые серверы оптимизируют вставку записей, если по ключевому полю построен монотонно возрастающий CLUSTERED индекс. В случае СК это элементарно, в случае ЕК — увы, обычно недостижимо. Кроме этого, INSERT в таблицу на стороне MANY (который происходит чаще) пойдет быстрее, т.к. REFERENCES будут проверяться по более быстрому индексу.

UPDATE

При обновлении поля, входящего в ЕК, придётся каскадно обновить и все связанные таблицы. Так, переименование Ленинграда в Санкт-Петербург потребует с нашем примере транзакции на несколько миллионов записей. Обновление любого атрибута в системе с СК приведет к обновлению только одной записи. Очевидно, что в случае распределенной системы, наличия архивов и т.п. ситуация только усугубится. Если обновляются поля не входящие в ЕК – быстродействие будет почти одинаковым.

Еще о CASCADE UPDATE

Далеко не все серверы БД поддерживают их на декларативном уровне. Аргументы «это у вас сервер кривой» в этом случае вряд ли корректны. Это вынуждает писать отдельную логику для обновления, что не всегда просто (приводился хороший пример — при отсутствии CASCADE UPDATE обновить поле, на которое есть ссылки, вообще невозможно — надо отключать REFERENCES или создавать копию записи, что не всегда допустимо (другие поля могут быть UNIQUE)).

DELETE

В случае СК будет выполняться быстрее, по той простой причине, что проверка REFERENCES пойдет по быстрому индексу.

А есть ли хорошие ЕК?

Hичто не вечно под Луной. Самый, казалось бы, надежный атрибут вдруг отменяется и перестаёт быть уникальным (далеко ходить не буду — рубль обычный и рубль деноминированный, примерам несть числа). Американцы ругаются на неуникальность номера социального страхования, Microsoft — на китайские серые сетевые платы с дублирующимися MAC-адресами, которые могут привести к дублированию GUID, врачи делают операции по смене пола, а биологи клонируют животных. В этих условиях (и учитывая закон неубывания энтропии) закладывать в систему тезис о неизменности ЕК — закладывать под себя мину. Их надо выделять в отдельный логический слой и по возможности изолировать от остальной информации. Так их изменение переживается куда легче. Да и вообще: однозначно ассоциировать сущность с каким-то из атрибутов этой сущности — ну, странно, что-ли. Hомер паспорта ещё не есть человек. СК же — это некая субстанция, именно и означающая сущность. Именно сущность, а не какой-то из её атрибутов.

Типичные аргументы сторонников ЕК

В системе с СК не осуществляется контроль правильности ввода информации

Это не так. Контроль не осуществлялся бы, если бы на поля, входящие в ЕК не было наложено ограничение уникальности. Очевидно, что если предметная область диктует какие-то ограничения на атрибуты ЕК, то они будут отражены в БД в любом случае.

В системе с ЕК меньше JOIN`ов, следовательно, запросы проще и разработка удобнее

Да, меньше. Hо, в системе с СК тривиально пишется:

CREATE VIEW PeopleEK AS

SELECT P.Family, P.Passport, C.Name

FROM People P INNER JOIN City C ON P.CityId = C.Id

И можно иметь все те же прелести. С более, правда, высоким быстродействием. При этом неплохо упомянуть, что в случае ЕК многим придется программировать каскадные операции, и, не дай Бог в распределённой среде, бороться с проблемами быстродействия. Hа фоне этого «короткие» запросы уже не кажутся столь привлекательными.

Введение ЕК нарушает третью нормальную форму

Вспомним определение:

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

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

Итак:

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

Таким образом, таблица, имеющая СК, легко может быть нормализована хоть до 5НФ. Точнее будет сказать, что СК к нормализации не имеют никакого отношения. Более того, введение СК уменьшает избыточность данных в БД, что вообще хорошо согласуется с идеологией нормализации. В сущности, нормализация и есть уменьшение информативности отдельных таблиц по определенным правилам. Только СК устраняют аномалии не внутри таблицы, а на межтабличном уровне (типа устранения каскадных обновлений). Так сказать, система с СК — святее Папы Римского :-). В самом деле – ситуация, когда при изменении одного из полей таблицы приходится изменять содержимое этого же поля в других записях ЭТОЙ ЖЕ таблицы, рассматривается как аномалия обновления. Но в системе с ЕК придется проделать то же самое В СВЯЗАННОЙ таблице при изменении ключевого атрибута на стороне 1 отношения 1:N. Очевидно, что эта ситуация с точки зрения физической реализации БД ничем не лучше. В системе с СК таких ситуаций не возникает.

Таблицы в системе с ЕК информативнее

Максимальной информативностью обладает таблица, содержащая всю БД в виде flat-file. Любое «повышение информативности таблиц» есть увеличение степени дублирования в них информации, что не обязательно есть хорошо. Да и вообще термин «Информативность таблицы» сомнителен. Видимо, более важна информативность БД, которая в обоих случаях одинакова.

Заключение:

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

{/codecitation}

Динамическое создание таблицы и полей во время выполнения программы

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Delphi в режиме разработки позволяет быстро добавлять и настраивать в вашем проекте компоненты для работы с базами данных, но есть ситуации, когда вам нужно создавать и конфигурировать объекты во время выполнения программы. Например, во время выполнения программы вам может понадобиться добавить колонку с вычисляемым полем (используя алгоритмы пользователя). Поэтому вопрос: как, не используя среды разработки, Инспектора Объектов и редактора TFields, создавать и сконфигурировать TField и другие компоненты для связки данных?

В следующем примере показано динамическое создание TTable, таблицы базы данных в связке с TTable, TFieldDefs, TFields, вычисляемых полей и подключение обработчика для события OnCalc.

Для начала выберите пункт New Application меню File. Будет создан новый проект с пустой формой, на которой мы и будет создавать на лету наши компоненты.

В секцию interface вашего модуля формы добавьте, как показано ниже, объявление обработчика события OnCalcFields и поля TaxAmount. Позже мы создадим TTable и назначим этот обработчик событию TTable OnCalcFields, который позволит при чтении каждой записи вызывать событие OnCalcFields, которое, в свою очередь, выполнит нашу процедуру TaxAmountCalc.

type

TForm1 = class(TForm)

procedure TaxAmountCalc(DataSet: TDataset);

private

TaxAmount: TFloatField;

end;

В секции implementation создайте обработчик события OnCalc как показано ниже:

procedure TForm1.TaxAmountCalc(DataSet: TDataset);

begin

Dataset[‘TaxAmount’] := Dataset[‘ItemsTotal’] *

(Dataset[‘TaxRate’] / 100);

end;

Создайте обработчик формы OnCreate как показано ниже (для получения дополнительной информации о создании обработчиков событий обратитесь к Delphi Users Guide, Chapter 4 «Working With Code»).

procedure TForm1.FormCreate(Sender: TObject);

var

MyTable: TTable;

MyDataSource: TDataSource;

MyGrid: TDBGrid;

begin

{ Создаем компонент TTable — связанная

таблица базы данных будет создана ниже. }

MyTable := TTable.Create(Self);

with MyTable do

begin

{ Определяем основную базу данных и таблицу.

Примечание: Test.DB пока не существует. }

DatabaseName := ‘DBDemos’;

TableName := ‘Test.DB’;

{ Назначаем TaxAmountCalc обработчиком события,

чтобы использовать его при наступлении события

OnCalcFields в MyTable. }

OnCalcFields := TaxAmountCalc;

{ Создаем и добавляем определения полей к массиву TTable

FieldDefs, затем создаем TField с использованием

информации из определения поля. }

with FieldDefs do

begin

Add(‘ItemsTotal’, ftCurrency, 0, false);

FieldDefs[0].CreateField(MyTable);

Add(‘TaxRate’, ftFloat, 0, false);

FieldDefs[1].CreateField(MyTable);

TFloatField(Fields[1]).DisplayFormat := ‘##.0%’;

{ Создаем вычисляемое TField, назначаем свойства,

и добавляем поле к массиву определений MyTable. }

TaxAmount := TFloatField.Create(MyTable);

with TaxAmount do

begin

FieldName := ‘TaxAmount’;

Calculated := True;

Currency := True;

DataSet := MyTable;

Name := MyTable.Name FieldName;

MyTable.FieldDefs.Add(Name, ftFloat, 0, false);

end;

end;

{ Создаем в базе данных новую таблицу,

используя в качестве основы MyTable. }

MyTable.CreateTable;

end;

{ Создаем компонент TDataSource

и назначаем его MyTable. }

MyDataSource := TDataSource.Create(Self);

MyDataSource.DataSet := MyTable;

{ Создаем табличную сетку, отображаем

на форме, и назначаем MyDataSource для

получения доступа к данным из MyTable. }

MyGrid := TDBGrid.Create(Self);

with MyGrid do

begin

Parent := Self;

Align := alClient;

DataSource := MyDataSource;

end;

{ Запускаем нашу конструкцию! }

MyTable.Active := True;

Caption := ‘Новая таблица ‘ MyTable.TableName;

end;

Ниже приведен полный исходный код проекта:

unit gridcalc;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, Grids, DBGrids, ExtCtrls, DBCtrls, DB,

DBTables, StdCtrls;

type

TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

procedure TaxAmountCalc(DataSet: TDataset);

private

TaxAmount: TFloatField;

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.TaxAmountCalc(DataSet: TDataset);

begin

Dataset[‘TaxAmount’] := Dataset[‘ItemsTotal’] *

(Dataset[‘TaxRate’] / 100);

end;

procedure TForm1.FormCreate(Sender: TObject);

var

MyTable: TTable;

MyDataSource: TDataSource;

MyGrid: TDBGrid;

begin

MyTable := TTable.Create(Self);

with MyTable do

begin

DatabaseName := ‘DBDemos’;

TableName := ‘Test.DB’;

OnCalcFields := TaxAmountCalc;

with FieldDefs do

begin

Add(‘ItemsTotal’, ftCurrency, 0, false);

FieldDefs[0].CreateField(MyTable);

Add(‘TaxRate’, ftFloat, 0, false);

FieldDefs[1].CreateField(MyTable);

TFloatField(Fields[1]).DisplayFormat := ‘##.0%’;

TaxAmount := TFloatField.Create(MyTable);

with TaxAmount do

begin

FieldName := ‘TaxAmount’;

Calculated := True;

Currency := True;

DataSet := MyTable;

Name := MyTable.Name FieldName;

MyTable.FieldDefs.Add(Name, ftFloat, 0, false);

end;

end;

MyTable.CreateTable;

end;

MyDataSource := TDataSource.Create(Self);

MyDataSource.DataSet := MyTable;

MyGrid := TDBGrid.Create(Self);

with MyGrid do

begin

Parent := Self;

Align := alClient;

DataSource := MyDataSource;

end;

MyTable.Active := True;

Caption := ‘Новая таблица ‘ MyTable.TableName;

end;

end.

{/codecitation}

Восстановление поврежденных таблиц

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Оформил: DeeCo

Автор: http://www.swissdelphicenter.ch

How to recover Data in a damaged Header of DbTables.

(Paradox or Dbase) Tables

If this problem occurs and we have not copies of data.

Paradox can»t directly open those damaged Tables so Paradox can»t repair those tables.

solution :

T1: the Damaged Table

1- We Have to create an empty Table (T2.Db or T2.Dbf) that have the same structure of damaged table (T1.DB or T1.Dbf).

2- With Dos Prompts or excutable batch File we have to execute this command:

Copy T2.Db T1.db T3.Db

or

Copy T2.Dbf T1.dbf T3.Dbf

3-Finally with paradox browser we can open T3 Table we have to delete bad records. and copy t3 to t1 table.

{/codecitation}

Database Desktop показывает содержимое таблиц шрифтом без русских букв

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Вопрос в кроссворде:

— Язык програмирования из трех букв.

Ответ:

— c

Для DBD 5.0 в файл c:\windows\pdoxwin.ini вставить в секцию:

[Properties]

SystemFont=Arial Cyr

Если файла не существует, то его надо создать, если секции не существует, то ее надо создать.

Для DBD 7.0 нужно испpавить pеестp — ключ:

HKCU\Software\Borland\DBD\7.0\ Preferences\Properties\SystemFont=»Arial Cyr»

{/codecitation}

Фильтр посредством логического поля

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Автор: Matthew Augier

В таблице имеется поле Customer:Boolean. Я хочу чтобы таблица показывала только Customer или только не-customer.

Установите ключ (вы должны иметь индекс для этого поля) одним из указанных способов:

tablex.SetRange([False],[False]) // для всех не-customer…

tablex.SetRange([True], [True]]) // для всех customer…

tablex.SetRange([False],[True]) // для всех записей…

{/codecitation}

Пример DbiAddFilter

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Автор: Mark Erbaugh

type

TmyFilter = record

Expr: CANExpr;

Nodes: array[0..2] of CANNode;

literals: array[0..7] of char;

end;

const

myFilter: TMyFilter = (Expr:

(iVer: 1; iTotalSize: sizeof(TMyFilter); iNodes: 3;

iNodeStart: sizeof(CANExpr); iLiteralStart: sizeof(CANExpr)

3 * sizeof(CANNode));

Nodes:

((canBinary: (nodeClass: nodeBinary; canOP: canEQ;

iOperand1: sizeof(CANNode); iOperand2: 2 * sizeof(CANNode))),

(canField: (nodeClass: nodeField; canOP: canField2;

iFieldNum: 0; iNameOffset: 0)),

(canConst: (nodeClass: nodeConst; canOP: canCONST2;

iType: fldZSTRING; iSize: 3; iOffset: 5)));

literals:

(‘T’, ‘Y’, ‘P’, ‘E’, #0, ‘I’, ‘N’, #0));

var

dbResult: DBIResult;

hFilter, hFilter1: hDBIFilter;

begin (* procedure SetupFilter *)

dbResult := DbiAddFilter(tblAP_.Handle, 1, 1,

False, addr(myFilter), nil, hFilter);

dbResult := DbiActivateFilter(tblAP_.Handle, hFilter);

tblAP_.First;

myFilter.nodes[0].canBinary.canOp := canNE;

dbResult := DbiAddFilter(tblAP1_.Handle, 1, 1,

False, addr(myFilter), nil, hFilter1);

dbResult := DbiActivateFilter(tblAP1_.Handle, hFilter1);

tblAP1_.First;

myFilter.nodes[0].canBinary.canOp := canEQ;

end;

Этот пример устанавливает два фильтра. Первый (применяемый к tblAP_) выводит все записи, где ТИП поля имеет значение ‘IN’. Второй (применяемый к tblAP1_) выводит все записи, где ТИП поля не имеет значения ‘IN’.

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

{/codecitation}

Правила для SetRange

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Автор: Josh

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

Попытаюсь изложить все попроще… Скажем, у меня есть индекс Field1; Field2; Field3, затем;

SetRangeStart;

Table1Field1.Value := x1;

Table1Field2.Value := y1;

Table1Field3.Value := z1;

SetRangeEnd;

Table1Field1.Value := x2;

Table1Field2.Value := y2;

Table1Field3.Value := z2;

ApplyRange;

Правила…

x1 должен равняться x2, если y или z определен

y1 должен равняться y2, если z определен

x должен быть определен, если y или z определены

y должен быть определен, если x определен

если x1 = x2 и никаких других критериев не определено, тогда y1 и y2 должны быть соответственно min/max значениями y

если x1 = x2 и y1 = y2 и никаких других критериев не определено, тогда z1 и z2 должны быть соответственно min/max значениями z

Я не знаю, поняли вы это или нет, но надеюсь это поможет…

{/codecitation}