Создание базы данных access из программы

Программирование
Нашей задачей будет создать базу данных из программы. Наша ОС Windows 98 и выше, СУБД ни одна не установлена, возможность копирования базы на другой ПК просто копированием файла будет.
Базу создадим средствами движка Jet встроенного в Windows, открывать ее потом можно будет в любой программе понимающей MDB, например родной Microsoft Access, размер базы до 2Гб.
Писать я буду в Turbo Delphi 2006, хотя это не принципиально.
Сначала вспомогательная процедура, создающая пустую базу
Procedure TfoMain.CreateMSAccessDatabase(filename : String);
var DAO: Variant;
    i:integer;
Const Engines:array[0..2] of string=('DAO.DBEngine.36', 'DAO.DBEngine.35', 'DAO.DBEngine');

    Function CheckClass(OLEClassName:string):boolean;
    var Res: HResult;
    begin
      Result:=CoCreateInstance(ProgIDToClassID(OLEClassName), nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IDispatch, Res)=S_OK;
    end;
begin
 For i:=0 to 2 do
   if CheckClass(Engines[i]) then
     begin
       DAO := CreateOleObject(Engines[i]);
       DAO.Workspaces[0].CreateDatabase(filename, ';LANGID=0x0409;CP=1252;COUNTRY=0', 32);
       exit;
     end;
 Raise Exception.Create('DAO engine could not be initialized');
end;

Пара переменных, которые нам потребуются
var sr : TSearchRec; //будем проверять наличие файла
  str:tstrings; // сюда сохраним список уже имеющихся в базе таблиц
  tableexist: Boolean; // для проверки наличия таблицы

Итак, проверяем есть ли файл, если нет то создаем его и конектимся компонентой ADOConnect
apl_path:=ExtractFileDir(application.ExeName);
  if findfirst(apl_path + '\cisad.mdb',0,sr)<>0 then CreateMSAccessDatabase(apl_path + '\cisad.mdb');

     self.ADOConnect.Connected:=false;
     self.ADOConnect.ConnectionString:='';
     self.ADOConnect.ConnectionString:=self.ADOConnect.ConnectionString+
      ' Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source='+apl_path + '\cisad.mdb'+';Mode=Share Deny None;Extended Properties="";Jet OLEDB:System database="";Jet OLEDB:Registry Path="";Jet OLEDB:Database Password="";';
     self.ADOConnect.ConnectionString:=self.ADOConnect.ConnectionString+
      'Jet OLEDB:Engine Type=4;Jet OLEDB:Database Locking Mode=0;Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="";Jet OLEDB:Create System Database=False;';
     self.ADOConnect.ConnectionString:=self.ADOConnect.ConnectionString+
      'Jet OLEDB:Encrypt Database=False;Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False';
     self.ADOConnect.Connected:=true;

     str:=TStringList.Create;
     self.ADOConnect.GetTableNames(str,false);

теперь можно создавать таблицы
tableexist := false;
  if str.Count > 0 then
    for i := 0 to str.Count - 1 do
      if str[i] = 'Settings' then
        tableexist := true;
  if not tableexist then
    try
      aqSQL.SQL.Clear;
      aqSQL.SQL.Add('create table Settings (                       ');
      aqSQL.SQL.Add('     id AUTOINCREMENT primary key,            ');
      aqSQL.SQL.Add('     daccountid  integer,                      ');
      aqSQL.SQL.Add('     dname  text(20),                          ');
      aqSQL.SQL.Add('     dvalue text(20),                          ');
      aqSQL.SQL.Add('     dtime date)                              ');
      aqSQL.ExecSQL;
    except
      on E: Exception do
        Trouble(self, E);
    end;

Процедура Trouble у нас обрабатывает все исключительные события, которые мы хотим обрабатывать. В данном случае будем просто записывать в лог все, что возникает.
procedure TfoMain.Trouble(Sender: TObject; E: Exception);
begin
 toLog('Exception (' + (sender as tobject).ClassName + ') : '+e.Message);
end;
procedure TfoMain.ToLog(s:string);
begin
  mmLog.Lines.Add(s);
  try writeln(log,FormatDateTime('YYYYMMDD HH:NN',now)+' : '+s); except end;
end;

Теперь можем работать с базой как обычно
Например процедура записи в созданную таблицу:
Procedure TfoMain.SaveSetting( Name, Value: string );
begin
  aqSet.Close;
  aqSet.SQL.Clear;
  aqSet.SQL.Add('select * from Settings where dname=' + #39 + Name + #39);
  aqSet.Open;
  if aqSet.RecordCount = 0 then
  try
    aqSet.Close;
    aqSet.SQL.Clear;
    aqSet.SQL.Add('insert into Settings ( dname,dvalue,dtime) ');
    aqSet.SQL.Add('  values ('+ #39 + name + #39 + ', ');
    aqSet.SQL.Add(#39 + '0' + #39 + ',' + #39 + datetimetostr(now) + #39 + ')');
    aqSet.ExecSQL;
  except
    on E: Exception do Trouble(self,E);
  end;
  ToLog('Save setting: ' + name + '=' + Value);
end;

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

11 комментариев

avatar
В корне не соглашусь с Вами, насчет <ведения логов и хранения настроек>. Для этих целей лучше использовать текстовые файлы, в крайнем случае XML.

Access морально устарел. Если в последствии приложение придется перевести на клиент-серверную архитектуру (например из-за увеличение числа пользователей и для повышения надежности и скорости работы), то придется переписывать кучу кода. Заменой Access могут стать:
- Microsoft SQL Server Compact
- Firebird Embedding
- MySql Embedding

Вывод: лучше сразу выбирать СУБД с учетом развития программы, чтобы потом не было мучительно <больно>.
avatar
Не соглашусь про кучу кода, по если по ado можно будет приконектиться, то изменения не такие уж и большие. И когда Access успел устареть не понятно, в состав Office 2010 он например входит. Я же написал, если размер базы никогда не превысит 2Гб, почему бы и нет? :)
avatar
Насчет остальных СУБД не знаю, но Microsoft SQL Server Compact вроде бы не поддерживает многопользовательскую работу с базой.
avatar
Не знаю, если vyachin сталкивался, рассказал бы:
avatar
Тоже отдам свой голос в пользу использования Access. Есть маленькие задачи, которые никогда расти не будут и где его использовать очень удобно. Как пример можно привести маленькое клиентское приложение для набивки информации, которая потом будет экспортироваться и относится в отчетную организацию на дискетке/флешке. Не у всех еще развит сетевой обмен. Существуют еще в природе и локальные приложения. Вот для них - это как раз может оказаться вполне оправданный выбор, не нужно будет устанавливать никакого лишнего софта, MS Jet уже в Windows и так присутствует.
avatar
И я про то.
Microsoft SQL Server Compact - колво соединений
MySql Embedding - только GPL (кому то важно, я шароварки например продавал)
Firebird Embedding - не пробовал, он вроде single user

Получается, что для каждой задачи можно подобрать инструмент. Не будете вы ведь в туфлях в футбол играть :)
avatar
Похоже местами. Автор склоняется больше в сторону MS SQL, видно близко ему, мне больше Оракл нравится, т.к. с него начинал :)
avatar
Встал недавно вопрос о переделке одной софтины, которая Oracle 9i использует. Много перерыл, ниже 10 ничего не нашел. Есть ли какая-нибудь 9i embedded? И может ссылочка есть? :)
avatar
Раньше для некоммерческого использования можно было обычный дистрибутив скачивать и все, упрощенных не было. Я еле нашел мелкий клиент размеров 8мб для 8i, в обычном варианте он сам знаешь какой.
Попробуй на 10, только там многих пакетов может не быть.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.