С Новым годом! Форум программистов, компьютерный форум, киберфорум
Delphi: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.73/26: Рейтинг темы: голосов - 26, средняя оценка - 4.73
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
MS Access

Многопоточная запись в базу данных access

25.10.2019, 22:06. Показов 5473. Ответов 32

Студворк — интернет-сервис помощи студентам
друзья столкнулся с такой ситуацией пишу в потоках данные в таблицу через adoquery. В итоге данные в таблице перемешаны, есть ли способ писать данные по порядку?
NAddTimeNumItem
225.10.2019 21:22:591
925.10.2019 21:22:591
825.10.2019 21:22:591
1025.10.2019 21:22:591
325.10.2019 21:23:002
1225.10.2019 21:22:591
225.10.2019 21:22:592
725.10.2019 21:23:002
425.10.2019 21:23:002
625.10.2019 21:23:002
1025.10.2019 21:23:003
1225.10.2019 21:23:002
825.10.2019 21:23:015
1125.10.2019 21:23:002
325.10.2019 21:23:015
925.10.2019 21:23:015
925.10.2019 21:23:016
525.10.2019 21:23:017
525.10.2019 21:23:018
для теста использую следующую конструкцию:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
implementation
 
{$R *.dfm}
var
 Potoks: array [1..12] of TPotok;
 n:integer;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
for n:=1 to 12 do
begin
Potoks[n]:=TPotok.Create(n);
 
end;
end;
 
constructor TPotok.Create(i:integer);
begin
Cnt:=i;
inherited Create(False);
FreeOnTerminate:=True;
end;
 
procedure TPotok.Execute;
var
Q:TADOQuery;
t:integer;
begin
CoInitialize(nil);
try
Form1.Label1.Caption := inttostr(Cnt);
Q:=TADOQuery.Create(Application);
Q.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\shar\multyaccessADO\ADO\thread.mdb; Persist Security Info=False;Jet OLEDB:Database Password=""';
try
for t:=1 to 1000 do
  begin
  Q.Close;
  Q.SQL.Clear;
  Q.SQL.Add('INSERT INTO Example (N, AddTime, NumItem) VALUES ("'+IntToStr(Cnt)+'","'+DateTimeToStr(Now)+'","'+IntToStr(t)+'")');
  Q.ExecSQL;
  end;
 
     finally
      Q.Free;
    end;
  finally
    CoUninitialize;
  end
end;
в гугле не нагуглил
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.10.2019, 22:06
Ответы с готовыми решениями:

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

Запись в базу данных Access
добрый день, не могу записать в базу данных, не понимаю в чем ошибка, на шарпе пишу не давно, поэтому знаю что ошибка в чем-то очень...

Запись в базу данных Access
Здравствуйте. Делаю дипломный проект. Есть необходимость записать в БД Access данные. Использую C#, приложение Windows Forms. Есть вариант...

32
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
26.10.2019, 01:17
Сразу возникает вопрос, а что вы вкладываете в понятие порядок? В таблице данные могут быть как угодно перемешаны, это не важно, а вот порядок вы уже сами задаете при выводе результатов, для чего принято использовать запросы с сортировкой.
Ну а многопоточность как-бы предполагает под собой отсутствие порядка и потом вы в потоке вот такое написали:
Delphi
1
Form1.Label1.Caption := inttostr(Cnt);
Нельзя так делать в потоке. Такой код совершенно непредсказуемо себя может вести. Оформите его так:
Delphi
1
Synchronize(procedure begin Form1.Label1.Caption := inttostr(Cnt); end);
0
5958 / 4534 / 1094
Регистрация: 29.08.2013
Сообщений: 28,141
Записей в блоге: 3
26.10.2019, 10:08
да и какие потоки при записи в БД?
движок все равно в одну таблицу 2 записи одновременно положить не может и ускорения не будет.

Цитата Сообщение от Пытливый Посмотреть сообщение
для чего принято использовать запросы с сортировкой.
+1

PS а где обработка ошибок?
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 12:36  [ТС]
Можно подробнее о запросе с сортировкой. Дело в том что в реальной программе могут записываться десятки и сотни тысяч записей (регистрационные данные с телеметрии пишутся каждую секунду) выгрузка в таблицу занимает много времени, вот и хочу ускорить как то данный процесс. и еще при загрузке в одном потоке основная форма зависает на время загрузки. приведенный выше мной пример тестовый. как правильно написать подскажите?

Добавлено через 6 минут
Цитата Сообщение от qwertehok Посмотреть сообщение
да и какие потоки при записи в БД?
движок все равно в одну таблицу 2 записи одновременно положить не может и ускорения не будет.


+1

PS а где обработка ошибок?
По поводу обработку ошибок как вы предлагаете их делать?
0
5958 / 4534 / 1094
Регистрация: 29.08.2013
Сообщений: 28,141
Записей в блоге: 3
26.10.2019, 13:06
Цитата Сообщение от Signum7 Посмотреть сообщение
выгрузка в таблицу занимает много времени
загрузка в таблицу
купите ссд и положите файлы на ссд

Цитата Сообщение от Signum7 Посмотреть сообщение
и еще при загрузке в одном потоке основная форма зависает на время загрузки. приведенный выше мной пример тестовый. как правильно написать подскажите?
а зачем вам форма для загрузки в бд? загружать надо сервисом

Цитата Сообщение от Signum7 Посмотреть сообщение
как вы предлагаете их делать?
написать хранимку которой вы будете передавать параметры
хранимка вставляет данные в таблицу
в случае некорректных данных, исключение пишет эту строку в таблицу с ошибками
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 13:09  [ТС]
Часть кода из реальной программы

Тут я свой диалог создаю:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//------------------------------------------------------------------------------
function TMainForm.GetParentWindowHandleForDialogs : HWND;
  begin
     try
      if Assigned(Screen.ActiveCustomForm) then begin
        Result := Screen.ActiveCustomForm.Handle;
      end else if Assigned(Application.MainForm) then begin
        Result := Application.MainFormHandle;
      end else begin
        Result := Application.Handle;
      end;
     except
     on E: Exception do
           ShowMessage(E.Message);
     end;
  end;
 
//------------------------------------------------------------------------------
function TMainForm.DMyShowMessage(const Msg,  Caption: string;
                                  const vtupe: integer) : integer ;
    begin
        Result := MessageBox(GetParentWindowHandleForDialogs,
                              PChar(Msg), PChar(Caption), vtupe);
    end;
//------------------------------------------------------------------------------
procedure TMainForm.Databaseeditor1Click(Sender: TObject);
begin
        BDmanager.Form2.Show;
end;
тут нахожу провайдера
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//------------------------------------------------------------------------------
procedure TMainForm.TestProvider;
  Function CheckMSProviderVersion: TProviderNum;
    Const
      CLSID_JETOLEDB_4_00: TGUID = '{DEE35070-506B-11CF-B1AA-00AA00B8DE95}';
      CLSID_ACEOLEDB_12_0: TGUID = '{3BE786A0-0366-4F5C-9434-25CF162E475E}';
      CLSID_ACEOLEDB_16_0: TGUID = '{3BE786A2-0366-4F5C-9434-25CF162E475E}';
      Var
        hR : HRESULT;
        OutParam : IUnknown;
      var
      iTmp, i: integer;
      Begin
        iTmp := Low(BDVar.ProviderArray);
        for i := iTmp to High(BDVar.ProviderArray) do
          begin
             BDVar.ProviderArray[i] := ePrNll;
          end;
        Result := ePrNot;
 
        hR := CoCreateInstance(CLSID_JETOLEDB_4_00,  Nil,  CLSCTX_INPROC_SERVER,
        IID_IDBInitialize,  OutParam);
      If (hR = S_OK) And (OutParam <> Nil) Then
      Begin
        OutParam := Nil;
        Result := ePr4;
        BDVar.ProviderArray[iTmp] := Result;
        INC(iTmp);
 
      End;
        hR := CoCreateInstance(CLSID_ACEOLEDB_12_0,  Nil,  CLSCTX_INPROC_SERVER,
        IID_IDBInitialize,  OutParam);
      If (hR = S_OK) And (OutParam <> Nil) Then
      Begin
        OutParam := Nil;
        Result := ePr12;
        BDVar.ProviderArray[iTmp] := Result;
       INC(iTmp);
 
      End;
        hR := CoCreateInstance(CLSID_ACEOLEDB_16_0,  Nil,  CLSCTX_INPROC_SERVER,
        IID_IDBInitialize,  OutParam);
      If (hR = S_OK) And (OutParam <> Nil) Then
      Begin
        OutParam := Nil;
        Result := ePr16;
        BDVar.ProviderArray[iTmp] := Result;
        INC(iTmp);
      End;
      if(iTmp > Low(BDVar.ProviderArray))then
      begin
         Result := ePrInn;
         BDVar.ProviderCnt := iTmp - 1;
      end else BDVar.ProviderCnt := Low(BDVar.ProviderArray);
End;
  begin
  BDvar.ProviderNum := ePrNot;
    Case CheckMSProviderVersion of
 
      ePrNot: MainForm.MyShowMessageErr('Не установлен MS Provider .. ', 'Ошибка');
      ePrInn: ConectProvider(BDvar, ePrInn);
      ePr4 : ConectProvider(BDvar, ePr4); // Microsoft.Jet.OLEDB.4.0
      ePr12: ConectProvider(BDvar, ePr12); // Microsoft.ACE.OLEDB.12.0
      ePr16: ConectProvider(BDvar, ePr16); //Microsoft.ACE.OLEDB.16.0
 
    Else MainForm.MyShowMessageErr('MS Provider не определен .. ', 'Ошибка');
  end;
end;
внутри программы
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
***
 Case prvar.ProviderArray[prvar.ProviderCnt] of
        ePr4 : BDVar.ProviderName := StrArray[0]; // Microsoft.Jet.OLEDB.4.0
        ePr12: BDVar.ProviderName := StrArray[1]; // Microsoft.ACE.OLEDB.12.0
        ePr16: BDVar.ProviderName := StrArray[2]; //Microsoft.ACE.OLEDB.16.0
      Else BDVar.ProviderName := StrArray[0];
      end;
***
BDVar.fConString := 'Provider=' + BDVar.ProviderName + 'Data Source=' +
                          BDVar.PathBD
                           //+ ';Persist Security Info=True;Password=123'//+ PasswordBD User ID=admin; <<-- тут выскакивает ошибка хотя пароли совпадают без пароля работает 
                           +';Persist Security Info=False;'
                           ;
***
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//------------------------------------------------------------------------------
procedure TMainForm.FormCreate(Sender: TObject);
var
b : boolean;
begin
    with MainForm do
      begin
       BorderStyle  := bsSizeToolWin;
       //align        :=alclient;
       windowstate  :=wsMaximized;
       //FormStyle:=fsStayOnTop;
       Left         := 0;
       Top          := 0;
       Height       := Screen.Height;
       Width        := Screen.Width;
     end;
     //--***************************************************************--------
     PathInApplication := ExtractFilePath(GetModuleName(0));
     NameInApplication  := ExtractFileName(GetModuleName(0));
     PasswordBD := Password;
       BDVar.PathBD := PathInApplication  + DataFoider
                      + DatabaseFolder ;
       if DirectoryExists(BDVar.PathBD) then
          begin
           BDVar.PathBD := BDVar.PathBD + NameBase;
              if FileExists(BDVar.PathBD) then
                TestProvider
                else
                begin
                   MainForm.MyShowMessageQUEST('Отсутствует база данных!' + CR +
                                                  'Указать путь к базе данных?',
                                                  'Ошибка', b);
                  if b  then
                    begin
                                                           //...
                    if OpenDialog.Execute then            // Не доработано
                    BDVar.PathBD := OpenDialog.FileName;  //  Доработать
                                                          //...
                    end else
                    Application.Terminate;
                end;
          end
       else
          begin
            MainForm.MyShowMessageErr('Отсутствует каталог с базой данных!',
                                                                  'Ошибка');
            Application.Terminate;
          end;
          //--***************************************************************---
 
 
 
end;
//------------------------------------------------------------------------------
procedure TMainForm.FormShow(Sender: TObject);
begin
     try
          ADOQuery1.Active := False;
          ADOConnection1.Close;
          ADOConnection1.ConnectionString := BDVar.fConString;
          ADOConnection1.Open();
          ADOConnection1.Connected := True;
          ADOQuery1.SQL.Clear;
          ADOQuery1.SQL.Add('SELECT * FROM ' + NameTableDB);
          ADOQuery1.Open;
          BDVar.fReConectBase := True;
      except
      on E: Exception do
      begin
      MainForm.MyShowMessageErr(E.ClassName+' Не удалось подключится к базе, код ошибки: '
                                 + E.Message + ' ' + CR + ' ' + 'Provider= ' + BDVar.ProviderName, 'Ошибка');
          BDVar.fReConectBase := False;
                  //  Тут дописать необходим действия в случае ошибки
                  //
 
      end;
     end;
end;
 
//------------------------------------------------------------------------------

дальше загружаю данные в дочернее окно
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//------------------------------------------------------------------------------
procedure TMainForm.FileOpen1Execute(Sender: TObject);
var
  Od : TOpenDialog;
begin
  //Диалог выбора файла.
  Od := OpenDialog;
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath(ParamStr(0));
    Od.Options := [ofFileMustExist];
 
   Od.Filter := 'Las files (*.las)|*.las|CSV files (*.csv)|*.CSV|Excel files (*.xls;*.xlsx)|*.xls;*.xlsx|Text files (*.txt)|*.txt|All files|*.*';;
   Od.FilterIndex := 1;
    if not Od.Execute then
    Exit;
      if not FileExists(Od.FileName) then
  begin
    MainForm.MyShowMessageErr('Файл с заданным именем не найден! Действие отменено.',
                                                                        'Ошибка');
    Exit;
  end;
 
  //if OpenDialog.Execute then
    CreateMDIChild(Od.FileName);
end;
 
***
 
//------------------------------------------------------------------------------
procedure TMainForm.CreateMDIChild(const Name: string);
var
  Child: TMDIChild;
  Fs : TFileStream;
  S  : UTF8String;  //UTF8String = AnsiString.
  stmp : string;
var
  Ex : OleVariant;
begin
 
  Child := TMDIChild.Create(Application);{ create a new MDI child window }
  Child.Caption := Name;
  stmp := ExtractFileExt(Name);
  if (stmp = '.txt') or (stmp = '.las') or (stmp = '.CSV')then
  begin
  if FileExists(Name) then
  begin
   //Загрузка данных из файла и их обработка.
  Fs := TFileStream.Create(Name, fmOpenRead + fmShareDenyWrite);
  try
    SetString(S, PChar(#0#0#0), 3);
    if (Fs.Read(S[1], 3) < 3) or (S <> #$EF#$BB#$BF) then
      Fs.Position := 0;
      SetLength(S, Fs.Size - Fs.Position);
      Fs.Read(S[1], Fs.Size);
      Child.Memo1.Text := UTF8Decode(S);
    finally
        FreeAndNil(Fs);
    end;
 
  end;
  end else
  if (stmp = '.xlsx') or (stmp = '.xls') then
  begin
   // Ex := CreateOleObject('Excel.Application');
   // Ex.Visible := False;  // скрыть Excel
                                // True;   // показать Excel
   // Ex.Application.DisplayAlerts:= True;   // показывать предупреждения
                                // False;  // не показывать предупреждения (игнорировать)
  end;
end;
после парсинга загружаю так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
 try
 
        MainForm.ADOQuery1.Insert;
        MainForm.ADOQuery1.FieldByName('datet').AsDateTime := t;
        MainForm.ADOQuery1.FieldByName('pressure1').AsFloat:= df ;
        MainForm.ADOQuery1.FieldByName('pressure2').AsFloat:= df2;
        MainForm.ADOQuery1.FieldByName('temperature').AsFloat:= tf;
        MainForm.ADOQuery1.FieldByName('depths').AsFloat:= 1.0;//пока нет данных
        MainForm.ADOquery1.Next;
        //MainForm.ADOQuery1.Active:=True;
      except
      on e:Exception do
      end;
как правильно сделать?
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
26.10.2019, 13:30
Можно существенно ускорить загрузку в базу, если использовать механизм транзакций для пачки записей, а не для одной как это происходит у вас по умолчанию. Какой версией Delphi вы пользуетесь? Если XE, то настоятельно рекомендую перейти на SQLite вместо Access, если нужна именно локальная база. Дело в том, что даже самый новый Акцесс использует очень старую версию SQL, где отсутствует масса крайне удобных SQL-конструкций.
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 13:46  [ТС]
Цитата Сообщение от Пытливый Посмотреть сообщение
Можно существенно ускорить загрузку в базу, если использовать механизм транзакций для пачки записей, а не для одной как это происходит у вас по умолчанию. Какой версией Delphi вы пользуетесь? Если XE, то настоятельно рекомендую перейти на SQLite вместо Access, если нужна именно локальная база. Дело в том, что даже самый новый Акцесс использует очень старую версию SQL, где отсутствует масса крайне удобных SQL-конструкций.
Embarcadero® RAD Studio 10.2 Version 25.0.26309.314

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

Хотел бы все таки использовать Access, но не знаю как оптимально написать код для правильной загрузки выгрузки то что я использую медленно, догадываюсь можно ускорить. у меня данные парсятся с файлов в базу или выгружаются из прибора в базу. далее эти данные выводятся в DBChart.
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
26.10.2019, 13:52
MySQL и SQLite это разные вещи. MySQL - клиент/серверная БД, а вот SQLite - это чисто клиентская база, как и Акцес она использует один файл.
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 14:06  [ТС]
Приму к сведению.
на данный момент нет времени новую базу изучать у меня сдача проекта исчисляется днями и уже за..д дымит, поэтому прошу помощи. Подскажите как написать хотя бы ПРАВИЛЬНО загрузку выгрузку (быстрое удаление всей таблицы) так как потеря данных критична, если можно пример кода запись/чтение для моего случая.

Добавлено через 3 минуты
Цитата Сообщение от Пытливый Посмотреть сообщение
Можно существенно ускорить загрузку в базу, если использовать механизм транзакций для пачки записей, а не для одной как это происходит у вас по умолчанию. Какой версией Delphi вы пользуетесь? Если XE, то настоятельно рекомендую перейти на SQLite вместо Access, если нужна именно локальная база. Дело в том, что даже самый новый Акцесс использует очень старую версию SQL, где отсутствует масса крайне удобных SQL-конструкций.
что такое механизм транзакций для пачки записей?
это
Delphi
1
Add('INSERT INTO Example (N, AddTime, NumItem) VALUES ("'+IntToStr(Cnt)+'","'+DateTimeToStr(Now)+'","'+IntToStr(t)+'")');
или что то другое?
0
Модератор
 Аватар для D1973
9908 / 6445 / 2455
Регистрация: 21.01.2014
Сообщений: 27,362
Записей в блоге: 3
26.10.2019, 14:41
Цитата Сообщение от Signum7 Посмотреть сообщение
что такое механизм транзакций для пачки записей?
Для Access - абсолютно ничего, просто пустой звук... А идея правильная, но не для этой недоСУБД
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
26.10.2019, 15:38
Да D1973, к сожалению вы правы, но я же Пытливый и проверил сам.
В качестве теста пишу в базу 5 раз по 10000 случайных строк. Транзакция настроена на пачку в 50 записей и вот такой печальный результат получается:
Transaction Off, Elapsed time: 9235
Transaction On, Elapsed time: 9047
Transaction Off, Elapsed time: 9062
Transaction On, Elapsed time: 9000
Transaction Off, Elapsed time: 8859
Transaction Off, Elapsed time: 8875
Transaction On, Elapsed time: 8984
Transaction On, Elapsed time: 9078
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 16:35  [ТС]
Вопрос на засыпку на сколько быстро можно переписать с Access на SQLite и что для этого нужно, с чем его едят? или для этого нужно засесть в гугл на неделю, осваивая новый метод?
0
26.10.2019, 18:42

Не по теме:

Цитата Сообщение от Пытливый Посмотреть сообщение
к сожалению вы правы
К сожалению, MS так старательно гробит свои, вроде бы и здравые поначалу, продукты что... Взять FoxPro, взять тот же Access (в прошлом веке он, как бы и нормальной локальной БД казался) - все похерено... Остается надеяться, что MS SQL Server такая судьба не так быстро постигнет...

0
5958 / 4534 / 1094
Регистрация: 29.08.2013
Сообщений: 28,141
Записей в блоге: 3
26.10.2019, 19:07
Цитата Сообщение от Signum7 Посмотреть сообщение
или для этого нужно засесть в гугл на неделю, осваивая новый метод?
для СУБД вам нужно знать SQL, остальное мелочи

если у вас не реальная задача, то и беспокоится не о чем
5 минут у вас будут файлы загружаться или 10, значения не имеет, миллион строк вы нагенерируете, а больше для учебной задачи и не нужно

Цитата Сообщение от Signum7 Посмотреть сообщение
что такое механизм транзакций для пачки записей?
если использовать Firedac, то почитайте про DML Array

Delphi
1
2
3
4
5
6
7
8
9
FDQuery1.SQL.Text := 'insert into MyTab values (:p1, :p2, :p3)';
// here FDQuery1.Params collection is filled by 3 parameters
FDQuery1.Params.ArraySize := 100;
for i := 0 to 100-1 do begin
  FDQuery1.Params[0].AsIntegers[i] := i;
  FDQuery1.Params[1].AsStrings[i] := 'qwe';
  FDQuery1.Params[2].Clear(i);
end;
FDQuery1.Execute(100, 0);
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
26.10.2019, 19:18
Нет, все не настолько печально. Для доступа к SQLite из XE у вас уже есть инструментарий - FireDac. Подключится к базе SQLite элементарно, единственная хитрость, надо выставить в настройках подключения флаг LockingMode = lmNormal
Не знаю зачем этот флаг выставлен по умолчанию в lmExclusive, но если его оставить в этом состоянии, нормально работать с базой SQLite - задачка не для слабонервных.
А вот нормальный менеджер для создания,изменения баз SQLite вам придется скачать. Очень хорош для первичного ознакомления SQLite Studio, к сожалению сейчас не поддерживается, но есть весьма неплохая альтернатива DBeaver который позволяет подключаться не только к SQLite, но и к другим популярным базам.
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
26.10.2019, 20:38  [ТС]
Цитата Сообщение от Пытливый Посмотреть сообщение
Нет, все не настолько печально. Для доступа к SQLite из XE у вас уже есть инструментарий - FireDac. Подключится к базе SQLite элементарно, единственная хитрость, надо выставить в настройках подключения флаг LockingMode = lmNormal
Не знаю зачем этот флаг выставлен по умолчанию в lmExclusive, но если его оставить в этом состоянии, нормально работать с базой SQLite - задачка не для слабонервных.
А вот нормальный менеджер для создания,изменения баз SQLite вам придется скачать. Очень хорош для первичного ознакомления SQLite Studio, к сожалению сейчас не поддерживается, но есть весьма неплохая альтернатива DBeaver который позволяет подключаться не только к SQLite, но и к другим популярным базам.
Вот погуглил по SQLite
https://yandex.fr/turbo?text=h... rax%2F&d=1
0
Модератор
 Аватар для D1973
9908 / 6445 / 2455
Регистрация: 21.01.2014
Сообщений: 27,362
Записей в блоге: 3
27.10.2019, 06:49
Вот только платный он, этот самый LiteDAC... Да и на кой ляд он нужен, если из коробки FireDAC идет...
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
27.10.2019, 14:03  [ТС]
Друзья вопрос актуален, на sqlite пока не буду переводить, не хочу переписывать процедуры. В будущих разработках сделаю на нем.

Добавлено через 1 минуту
Задача реальная не учебный проект

Добавлено через 3 минуты
Цитата Сообщение от qwertehok Посмотреть сообщение
для СУБД вам нужно знать SQL, остальное мелочи

если у вас не реальная задача, то и беспокоится не о чем
5 минут у вас будут файлы загружаться или 10, значения не имеет, миллион строк вы нагенерируете, а больше для учебной задачи и не нужно


если использовать Firedac, то почитайте про DML Array

Delphi
1
2
3
4
5
6
7
8
9
FDQuery1.SQL.Text := 'insert into MyTab values (:p1, :p2, :p3)';
// here FDQuery1.Params collection is filled by 3 parameters
FDQuery1.Params.ArraySize := 100;
for i := 0 to 100-1 do begin
  FDQuery1.Params[0].AsIntegers[i] := i;
  FDQuery1.Params[1].AsStrings[i] := 'qwe';
  FDQuery1.Params[2].Clear(i);
end;
FDQuery1.Execute(100, 0);
Я так понял
Delphi
1
FDQuery1.Params.ArraySize := 100;
-по сто записей за раз?

Добавлено через 8 минут
Цитата Сообщение от Signum7 Посмотреть сообщение
Друзья вопрос актуален, на sqlite пока не буду переводить, не хочу переписывать процедуры. В будущих разработках сделаю на нем.

Добавлено через 1 минуту
Задача реальная не учебный проект

Добавлено через 3 минуты

Я так понял
Delphi
1
FDQuery1.Params.ArraySize := 100;
-по сто записей за раз?
вот нашел про DML Array

/questions/828576/the-fastest-way-to-load-an-array-dml-in-delphi-firedac

Добавлено через 8 минут
ссылку не дает вставить полностью qaruточкаsite...

Добавлено через 38 минут
цитата с сайта
Самый быстрый способ загрузить массив DML в Delphi FireDAC
Я использую Delphi XE8 с FireDAC для загрузки большой базы данных SQLite. Для этого я использую технику выполнения Array DML для эффективной вставки большого количества записей одновременно, например:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
FDQueryAddINDI.SQL.Text := 'insert into indi values ('
  + ':indikey, :hasdata, :gedcomnames, :sex, :birthdate, :died, '
  + ':deathdate, :changed, :eventlinesneedprocessing, :eventlines, '
  + ':famc, :fams, :linkinfo, :todo, :nextreportindi, :firstancestralloop'
  + ')';
FDQueryAddINDI.Params.Bindmode := pbByNumber; {more efficient than by name }
FDQueryAddINDI.Params.ArraySize := MaxParams; { large enough to load all of them } 
 
NumParams := 0;
repeat
  { the code to determin IndiKey,... is not shown, but goes here }
 
  FDQueryAddINDI.Params[0].AsStrings[NumParams] := IndiKey;   
  FDQueryAddINDI.Params[1].AsIntegers[NumParams] := HasData;
  FDQueryAddINDI.Params[2].AsStrings[NumParams] := GedcomNames;
  FDQueryAddINDI.Params[3].AsStrings[NumParams] := Sex;
  FDQueryAddINDI.Params[4].AsStrings[NumParams] := Birthdate;
  FDQueryAddINDI.Params[5].AsIntegers[NumParams] := Died;
  FDQueryAddINDI.Params[6].AsStrings[NumParams] := Deathdate;
  FDQueryAddINDI.Params[7].AsStrings[NumParams] := Changed;
  FDQueryAddINDI.Params[8].AsIntegers[NumParams] := EventLinesNeedProcessing;
  FDQueryAddINDI.Params[9].AsStrings[NumParams] := EventLines;
  FDQueryAddINDI.Params[10].AsIntegers[NumParams] := FamC;
  FDQueryAddINDI.Params[11].AsIntegers[NumParams] := FamS;
  FDQueryAddINDI.Params[12].AsIntegers[NumParams] := Linkinfo;
  FDQueryAddINDI.Params[13].AsIntegers[NumParams] := ToDo;
  FDQueryAddINDI.Params[14].AsIntegers[NumParams] := NextReportIndi;
  FDQueryAddINDI.Params[15].AsIntegers[NumParams] := FirstAncestralLoop;
  inc(NumParams);
until done;
FDQueryAddINDI.Params.ArraySize := NumParams;  { Reset to actual number }
 
FDQueryAddINDI.Execute(LogoAppForm.FDQueryAddINDI.Params.ArraySize);
Я протестировал вставку 33 790 записей, изменяющих размер массива (количество записей для загрузки за выполнение), и рассчитал время загрузки как с pbByName (для эмуляции), так и с pbByNumber (используя вставку нескольких значений).

Это было время:

Arraysize: 1, Executes: 33,790, Timing: 1530 ms (pbByName), 1449 ms (pbByNumber)
Arraysize: 10, Executes: 3,379, Timing: 1034 ms (pbByName), 782 ms (pbByNumber)
Arraysize: 100, Executes: 338, Timing: 946 ms (pbByName), 499 ms (pbByNumber)
Arraysize: 1000, Executes: 34, Timing: 890 ms (pbByName), 259 ms (pbByNumber)
Arraysize: 10000, Executes: 4, Timing: 849 ms (pbByName), 227 ms (pbByNumber)
Arraysize: 20000, Executes: 2, Timing: 594 ms (pbByName), 172 ms (pbByNumber)
Arraysize: 50000, Executes: 1, Timing: 94 ms (pbByName), 94 ms (pbByNumber)
Теперь интересная вещь об этих временах заключается в том, что загрузка этих 33 790 записей в TCollection занимает полные 93 мс при каждом запуске теста. Неважно, добавляются ли они по одному за раз или 10000 за раз, эти накладные расходы на заполнение TCollection of Params всегда присутствуют.

Для сравнения я сделал больший тест с 198 522 вставками только для pbByNumber:
Arraysize: 100, Executes: 1986, Timing: 2774 ms (pbByNumber)
Arraysize: 1000, Executes: 199, Timing: 1371 ms (pbByNumber)
Arraysize: 10000, Executes: 20, Timing: 1292 ms (pbByNumber)
Arraysize: 100000, Executes: 2, Timing: 894 ms (pbByNumber)
Arraysize: 1000000, Executes: 1, Timing: 506 ms (pbByNumber)
Для всех случаев этого теста накладные расходы на загрузку TCollection Params занимают около 503 мс.

Таким образом, загрузка TCollection составляет около 400 000 записей в секунду. Это значительная часть времени вставки, и как только я начну работать с большими базами данных миллионами, это добавленное время будет весьма заметно для пользователя моей программы.

Я хотел бы улучшить это, но я еще не нашел способ ускорить загрузку параметров.

Обновление 2: я смог добиться улучшения примерно в 10% времени, поместив весь свой код между StartTransaction и Commit, так что все блоки будут обрабатываться одновременно.

Но я все еще ищу способ загрузить TCollection of Params намного быстрее.

Еще одна идея:

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

Это будет работать так:
Delphi
1
2
 FDQueryAddINDI.Params.ParamValues['indikey;hasdata;gedcomnames;sex;birthdate;died;deathdate;changed;eventlinesneedprocessing;eventlines;famc;fams;linkinfo;todo;nextreportindi;firstancestralloop']
       := VarArrayOf([Indikey, 0, ' ', ' ', ' ', 0, ' ', ' ', 1, ' ', -1, -1, -1, -1, -1, -1]);
0
1 / 1 / 0
Регистрация: 30.03.2017
Сообщений: 133
13.11.2019, 01:23  [ТС]
Доброго времени суток
столкнулся с такой проблемой, создал тестовый проект для быстрой загрузки данных в sqlite.
таблица заполняется верно и быстро, но не отображается в dbgrid. при попытке включить
Delphi
1
DataModule2.FDQuery1.Active := true;
выскакивает предупреждение: error: unique constraint failed: data.id (имя таблицы и поля)

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

Delphi
1
2
3
4
5
6
procedure TDataModule2.DataModuleCreate(Sender: TObject);
begin
   path := ExtractFilePath(ParamStr(0));
   FDConnection1.Params.Add('Database='+path+'Database\dbm.db');
   FDConnection1.Connected := True;
end;
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
procedure TForm1.Button2Click(Sender: TObject);
var i : integer;
begin
       DataModule2.FDQuery1.SQL.Text := 'insert into data values ( :p1, :p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9)';
       DataModule2.FDQuery1.Params.ArraySize := 10000;
      try
      for I := 0 to 10000 -1 do
       begin
          DataModule2.FDQuery1.Params[0].Asintegers[i] := i+1;
          DataModule2.FDQuery1.Params[1].AsStrings[i] := 'Ok';
          DataModule2.FDQuery1.Params[2].AsDateTimes[i] := now;
          DataModule2.FDQuery1.Params[3].AsFloats[i]:= double(i) + 0.1 ;
          DataModule2.FDQuery1.Params[4].AsFloats[i]:= double(i) + 0.1 * 0.2;
          DataModule2.FDQuery1.Params[5].AsFloats[i]:= double(i) + 0.1 * 3;
          DataModule2.FDQuery1.Params[6].AsFloats[i]:= 1.0;
          DataModule2.FDQuery1.Params[7].AsIntegers[i]:= i * 3;
          DataModule2.FDQuery1.Params[8].AsStrings[i]:= 'Title';
      end;
        DataModule2.FDQuery1.Params.ArraySize := i;
        DataModule2.FDQuery1.Execute(10000, 0);
        DataModule2.FDQuery1.Connection.Commit;
      except
      on e:Exception do
      begin
        DataModule2.FDQuery1.Connection.Rollback;
        raise;
      end;
      end;
end;
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
13.11.2019, 01:23
Помогаю со студенческими работами здесь

Запись в базу данных access
При попытке выполнения кода выдаёт ошибку &quot;Ошибка синтаксиса в инструкции INSERT INTO&quot; и подсвечивает строку...

запись из txt файла в базу данных Access
Здравствуйте, я не очень хорошо пока пишу на ASP, но мне на данный момент нужно решить такую задачу: есть документ txt, его содержание...

Как программно добавить запись в базу данных access через datagridview?
Проблема заключается в следующем: Когда заполняю таблицу с клавиатуры, то данные с datagridview сохраняются в бд, а когда таблица...

Запись в базу access ADO
база access подключаюсь через ADO если несколько человек работают с программой то при изменении записи одним из них не происходит...

Как заполнить базу данных Access с помощью vba в том же access и считать из нее инфу?
Прошу помочь в азах. Как заполнить базу данных Access с помощью vba в том же access и считать из нее инфу? Спасибо.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru