Правильный экспорт из DBGrid/DataSet в файл

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
wwswowsogon
постоялец
Сообщения: 157
Зарегистрирован: 23.12.2008 19:41:37

Правильный экспорт из DBGrid/DataSet в файл

Сообщение wwswowsogon »

Всем доброго времени суток!
Продолжаю разбираться с СУБД/Firebird.

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

Код, например, такой (не обращайте внимания на кривизну;)):

Код: Выделить всё

Main.SQLQuery1.First;

  for i := 1 to Main.SQLQuery1.RecordCount - 1 do
    begin
          s0 := Main.SQLQuery1.Fields.Fields[0].AsString;
          s1 := Main.SQLQuery1.Fields.Fields[1].AsString;
          s2 := Main.SQLQuery1.Fields.Fields[2].AsString;
          s3 := Main.SQLQuery1.Fields.Fields[3].AsString;
          s4 := Main.SQLQuery1.Fields.Fields[4].AsString;
          s5 := Main.SQLQuery1.Fields.Fields[5].AsString;
          s6 := Main.SQLQuery1.Fields.Fields[6].AsString;
          s := s0 + ';' + s1 + ';' + s2 + ';' + s3 + ';' + s4 + ';' + s5 + ';' + s6;
          WriteLn(CSVFile, s);
      Main.SQLQuery1.Next;
    end;


Я зашёл в тупик: экспортируется только та часть набора, которая непосредственно видна в DBGrid. Т.е. из, например, 400 записей формируются только видимые 20-30. На мой взгляд, это странно, это было бы логично, если бы я брал данные из датасета таблицы:

Код: Выделить всё

Main.DBGrid1.DataSource.DataSet.First;


и так далее. Но ведь экспорт в данном случае происходит непосредственно из датасета? Или нет?
Почему так происходит и как с эти бороться?
sign
энтузиаст
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Сообщение sign »

Я работаю с MySQL, но не думаю, что есть сильные отличия в нижеприведённом коде.

Код: Выделить всё

Main.SQLQuery1.First;
while not Main.SQLQuery1.EOF do begin
 { операции с данными }
  Main.SQLQuery1.Next;
end;
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3071
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

wwswowsogon писал(а):Но ведь экспорт в данном случае происходит непосредственно из датасета? Или нет?

Помнится, в настройках соединения или query есть что-то про выдачу данных целиком или порциями. Покопайтесь в документации. Fetch или как-то так.
Аватара пользователя
alexs
долгожитель
Сообщения: 4069
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

wwswowsogon
При работе с наборами данных надо использовать конструкцию

Код: Выделить всё

DS.First;
while not DS.EOF do
begin
  DS.Next;
end

Гарантированно будут выбраны все данные.
Цикл for сработает только по уже отфетченным данны. А сколько их будет стянуто с сервера - зависит от конкретных компонент и сервера.
wwswowsogon
постоялец
Сообщения: 157
Зарегистрирован: 23.12.2008 19:41:37

Сообщение wwswowsogon »

Да, действительно,

Код: Выделить всё

Main.SQLQuery1.EOF


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

Код: Выделить всё

Main.SQLQuery1.RecordCount - 1


alexs писал(а):wwswowsogon
При работе с наборами данных надо использовать конструкцию
Гарантированно будут выбраны все данные.
Цикл for сработает только по уже отфетченным данны. А сколько их будет стянуто с сервера - зависит от конкретных компонент и сервера.


-видимо, это и есть исчерпывающий ответ. :) Спасибо большущее за наводку, сам бы ещё долго втыкал, что и как происходит в SQLQuery.
Доброго здравия и всех благ!
Аватара пользователя
alexs
долгожитель
Сообщения: 4069
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

Ну можно ещё, конечно, можно вызвать перед циклом FetchAll - если он есть у компоненты. Но не все данный метод реализуют.
Lucifer
постоялец
Сообщения: 133
Зарегистрирован: 05.01.2014 21:39:03
Откуда: Новороссийск

Сообщение Lucifer »

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

Код: Выделить всё

function to_sylk(ADataSet: TDataSet; const SaveHeader: Boolean = True): String;
var
  iRow, iCol: Integer;
  tmpFile: String;
  mText: TStringList;
  SR: TSearchRec;
begin
//  LazGetLanguageIDs(Lang, FallbackLang);
  try
    // Сделаем попытку удаления всех ранее нагенеренных файлов
    if FindFirst(GetTempDir + '*.slk', faAnyFile, SR) = 0 then
    begin
      repeat
        DeleteFile(GetTempDir + SR.Name)
      until
        FindNext(SR) <> 0;
      FindClose(SR);
    end;
  except
    // Возможная обработка ошибок
  end;
  // Генерируем сам файл
  try
    tmpFile := GetTempDir + GUID.NewGuid.ToString(True) + '.slk';
    mText := TStringList.Create;
    mText.Clear;
    ADataSet.First;
    iRow := 0;
    iCol := 0;
    mText.Append('ID;PWXL;N;E');
    ADataSet.DisableControls;
    if SaveHeader then
      for iCol := 0 to ADataSet.FieldCount - 1 do
        mText.Append('C;Y1;X' + (iCol + 1).ToString + ';K"' + ADataSet.Fields[iCol].FieldName + '"');
    while not ADataSet.EOF do
    begin
      for iCol := 0 to ADataSet.FieldCount - 1 do
        mText.Append('C;Y' + (iRow + 2).Tostring + ';X' + (iCol + 1).ToString + ';K"' + ADataSet.Fields[iCol].AsString + '"');
      ADataSet.Next;
      Inc(iRow);
    end;
    mText.Append('E');
    mText.Text := UTF8ToCP1251(mText.Text);
    mText.SaveToFile(tmpFile);
    Result := tmpFile;
  finally
    ADataSet.EnableControls;
    mText.Free;
  end;
end;
DedFrend
постоялец
Сообщения: 157
Зарегистрирован: 25.11.2018 11:21:50

Сообщение DedFrend »

Для Lucifer
А что это за конструкция?
Lucifer писал(а):(iCol + 1).ToString
Lucifer
постоялец
Сообщения: 133
Зарегистрирован: 05.01.2014 21:39:03
Откуда: Новороссийск

Сообщение Lucifer »

DedFrend писал(а):Для Lucifer
А что это за конструкция?
Lucifer писал(а):(iCol + 1).ToString


Ну, напиши IntToStr(iCol + 1). Ровно то же самое, но я привык пользоваться ToString
Ответить