数据来自 .DBF 文件未复制到 SQLite 文件



我正在使用带有Windows 7 OS的Delphi XE5。

我有.dbf文件,我需要将该文件数据移动到SQLite文件。

观察:当我在 NaviCat for SQLite 中导入此文件时,我看到 ASCII 格式的数据。从 ADODataset(保存文件.dbf中的数据)复制数据时,我看到 ftWideString 和 ftWideMemo,我在为 TFDQuery 类型的"查询"组件分配适当的数据类型时是否犯了错误?但情况并非总是如此,即.dbf文件也可能包含正常的字母数字字符。目的是将任何类型的数据从.dbf文件发布到 SQLite 文件。

下面的过程将数据发布到 SQLite 文件中,我在发布数据时没有收到任何错误,但是当我在 NaviCat 中打开 SQLite 文件时,我没有看到空白记录。

procedure TfrmMainForm.InsertDatabtnClick(Sender: TObject);

我正在尝试使用以下代码:

法典:

const
  MyDBFile = 'C:TempDBMYSQLightDB.db';
type
  TfrmMainForm = class(TForm)
    ADOConnection1: TADOConnection;
    CreateTablebtn: TButton;
    ADODataSet1: TADODataSet;
    DataSource1: TDataSource;
    FDGUIxWaitCursor1: TFDGUIxWaitCursor;
    InsertDatabtn: TButton;
    FDQuery1: TFDQuery;
    SQLConnection1: TSQLConnection;
    ADODataSet2: TADODataSet;
    procedure CreateTablebtnClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure InsertDatabtnClick(Sender: TObject);
  private
    { Private declarations }
    Connection : TFDConnection;
    DriverLink : TFDPhysSQLiteDriverLink;
    Table : TFDTable;
    Query : TFDQuery;
  public
    { Public declarations }
  end;
var
  frmMainForm: TfrmMainForm;
implementation
{$R *.dfm}

procedure TfrmMainForm.FormShow(Sender: TObject);
begin
  CreateComponents;
end;
procedure TfrmMainForm.CreateTablebtnClick(Sender: TObject);
begin
  ConnectTodatabaseFile;
end;
procedure TfrmMainForm.ConnectTodatabaseFile;
var
  dbf_folder : string;
begin
  dbf_folder:='C:TempDB';//set your dbf folder location here
  ADOConnection1.LoginPrompt:=false;
  ADOConnection1.ConnectionString:=Format('Provider=Microsoft.JET.OLEDB.4.0;Data Source=%s;Extended Properties=dBase IV;',[dbf_folder]);
  ADODataSet1.ConnectionString:=Format('Provider=Microsoft.JET.OLEDB.4.0;Data Source=%s;Extended Properties=dBase IV;',[dbf_folder]);
  try
    ADOConnection1.Connected:=True;
    ADODataSet1.CommandText:='Select * from MyFileName.dbf'; //make your SQL query using the name of the dbf file
    ADODataSet1.Open;
    CreateSQLiteTable;
    ShowMessage('Table created successfully');
  except
    on E : Exception do
      ShowMessage(E.Message);
  end;
end;
procedure TfrmMainForm.CreateSQLiteTable;
var
  FFieldName, FCreateSQL : string;
  FColumnCount : Integer;
begin
  FCreateSQL := 'Create Table MyTable1 (';
  for FColumnCount := 0 to ADODataSet1.FieldCount - 1 do
  begin
    FFieldName := ADODataSet1.Fields[FColumnCount].FieldName;
    FCreateSQL := FCreateSQL + FFieldName + ' ' + FieldTypeToSQLString(ADODataSet1.Fields[FColumnCount].DataType, ADODataSet1.Fields[FColumnCount].DataSize);
    if FColumnCount <> ADODataSet1.FieldCount - 1 then
      FCreateSQL := FCreateSQL + ', ';
  end;
  FCreateSQL := FCreateSQL + ')';
  Query.Close;
  Query.SQL.Clear;
  Query.SQL.Add(FCreateSQL);
  Query.ExecSQL;
end;
procedure TfrmMainForm.InsertDatabtnClick(Sender: TObject);
var
  FSQLString : String;
  FColumnCount : Integer;
begin
  Query.Close;
  Query.CachedUpdates := True;
  Query.SQL.Clear;
  Query.SQL.Add('Select * from MyTable1 where 1 = 2');
  Query.Active := True;
  ADODataSet1.First;
  while not ADODataSet1.eof do
  begin
    Query.Insert;
    for FColumnCount := 0 to ADODataSet1.FieldCount - 1 do
    begin
      Query.Fields[FColumnCount].Value := ADODataSet1.Fields[FColumnCount].Value;
    end;
    ADODataSet1.Next;
  end;
  Query.Edit;
  Query.Post;
  Query.CommitUpdates;
  ShowMessage('Data Inserted');
end;
procedure TfrmMainForm.CreateComponents;
begin
  DriverLink := TFDPhysSQLiteDriverLink.Create(Self);
  Connection := TFDConnection.Create(self);
  Connection.Params.Values['DriverID'] := 'SQLite';
  Connection.Params.Values['Database'] := MyDBFile;
  Connection.Connected := True;
  Table := TFDTable.Create(self);
  Query := TFDQuery.Create(self);
  Query.Connection := Connection;
  Table.Connection := Connection;
end;
procedure TfrmMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DeleteComponents;
end;
procedure TfrmMainForm.DeleteComponents;
begin
  Connection.Free;
  DriverLink.Free;
  Table.Free;
  Query.Free;
end;
Function TfrmMainForm.FieldTypeToSQLString(T : TFieldType; L : Longint) : String;
Begin
  case T of
    ftString : Result := 'VARCHAR('+IntToStr(L)+')';
    ftSmallint : Result := 'SMALLINT';
    ftInteger : Result := 'INTEGER';
    ftWord : Result := 'SMALLINT';
    ftBoolean : Result := 'BOOLEAN';
    ftFloat : Result := 'FLOAT';
    ftCurrency : Result := 'MONEY';
    ftBCD : Result := 'DECIMAL';
    ftDate : Result := 'DATE';
    ftTime : Result := 'TIME';
    ftDateTime : Result := 'TIMESTAMP';
    ftBytes : Result := 'BLOB('+IntToStr(L)+',2)';
    ftVarBytes : Result := 'BLOB('+IntToStr(L)+',2)';
    ftAutoInc : Result := 'AUTOINC';
    ftBlob : Result := 'BLOB('+IntToStr(L)+',1)';
    ftMemo : Result := 'BLOB('+IntToStr(L)+',1)';
    ftGraphic : Result := 'BLOB('+IntToStr(L)+',5)';
    ftFmtMemo : Result := 'BLOB('+IntToStr(L)+',3)';
    ftParadoxOle : Result := 'BLOB('+IntToStr(L)+',4)';
    ftDBaseOle : Result := 'BLOB('+IntToStr(L)+',4)';
    ftTypedBinary : Result := 'BLOB('+IntToStr(L)+',2)';
    ftFixedChar : Result := 'CHAR('+IntToStr(L)+')';
    ftWideString : Result := 'VARCHAR('+IntToStr(L)+')';
    ftWideMemo : Result := 'NTEXT';
    ftLargeInt : Result := 'INTEGER'
  else
    Result := 'UNKNOWN!';
  end;
End;
end.

在下面的循环中,你应该为你插入的每一行调用 Query.Post,并且由于你已经调用了Query.Insert,所以你不需要调用Query.Edit。 无论如何调用.编辑,然后立即调用 。Post一事无成,但我不确定这只是一个粗心的错误,还是对如何使用数据集缺乏根本的缺乏理解。

  while not ADODataSet1.eof do
  begin
    Query.Insert;
    for FColumnCount := 0 to ADODataSet1.FieldCount - 1 do
    begin
      Query.Fields[FColumnCount].Value := ADODataSet1.Fields[FColumnCount].Value;
    end;
    //Query.Edit;
    Query.Post;
    ADODataSet1.Next;
  end;
  Query.CommitUpdates;
  ShowMessage('Data Inserted');

鉴于这些基本错误和我在评论中指出的错误,我认为您应该从头到尾非常仔细地检查您的代码。

关于你自己的回答,我有几点意见:

  1. 您不需要继续调用 Query.Close,因为调用 Query.ExecSQL 不会使其保持打开状态。

  2. while not AdoDataset1.Eof循环之前设置插入 SQL 的参数化版本,然后只在循环内提供参数值,会更好(在 SqlInjection 上下文中更安全)。 如果你这样做,你将避免很多混乱的QuotedStr(),并且在任何情况下,你应该避免动态构造SQL,因为SqlInjection点。

下面是我将数据发布到 SQLite 文件的方式。

法典:

procedure TfrmMainForm.InsertDatabtnClick(Sender: TObject);
var
  FSQLString : WideString;
  FColumnCount : Integer;
  FSQLPrepared : Boolean;
begin
  FSQLPrepared := False;
  Query.Close;
  Query.CachedUpdates := True;
  if not ADODataSet1.Active then
    ADODataSet1.Active := True;
  ADODataSet1.First;
  while not ADODataSet1.eof do
  begin
    //Also script component could be used to execute bulk amount of insert SQL
    FSQLString := 'Insert Into MyTable1 Values(';
    for FColumnCount := 0 to ADODataSet1.FieldCount - 1 do
    begin
      //Query.Fields[FColumnCount].Value := ADODataSet1.Fields[FColumnCount].Value;
      FSQLString := FSQLString + QuotedStr(ADODataSet1.Fields[FColumnCount].AsString);
      if FColumnCount <> ADODataSet1.FieldCount - 1 then
        FSQLString := FSQLString + ', ';
    end;
    FSQLString := FSQLString + ')';
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Add(FSQLString);
    if not FSQLPrepared then
    begin
      Query.Prepared := True;
      FSQLPrepared := True;
    end;
    Query.ExecSQL;
    ADODataSet1.Next;
  end;
  ShowMessage('Data Inserted');
end;

我通过修改问题中提到的过程以另一种方式解决了它。在提交对数据库的更改之前,刚刚添加了以下语句。

Query.ApplyUpdates(0);

循环中不需要 "Query.Post;" 语句。

完整程序:

procedure TfrmMainForm.InsertDatabtnClick(Sender: TObject);
var
  FSQLString : String;
  FColumnCount : Integer;
begin
  Query.Close;
  Query.CachedUpdates := True;
  Query.SQL.Clear;
  Query.SQL.Add('Select * from MyTable1 where 1 = 2');
  Query.Active := True;
  ADODataSet1.First;
  while not ADODataSet1.eof do
  begin
    Query.Insert;
    for FColumnCount := 0 to ADODataSet1.FieldCount - 1 do
    begin
      Query.Fields[FColumnCount].Value := ADODataSet1.Fields[FColumnCount].Value;
    end;
    ADODataSet1.Next;
  end;
  Query.ApplyUpdates(0);
  Query.CommitUpdates;
  ShowMessage('Data Inserted');
end;

相关内容

  • 没有找到相关文章

最新更新