2016-04-26 12 views
-3

Windows 7 OSでDelphi XE5を使用しています。.DBFファイルのデータがSQLiteファイルにコピーされない

私は.DBFファイルと私はSQLiteのファイルに移動する必要があり、このファイルデータを持っています。

観察:私はSQLiteのためのNavicatでこのファイルをインポートすると、そこに私はASCII形式のデータを参照してください。 ADODataset(.dbfファイルのデータを保持する)からデータをコピーするときに、ftWideStringとftWideMemoが表示されますが、TFDQuery型の「クエリ」コンポーネントに適切なデータ型を割り当てていますか?しかし、常にそうではない。すなわち、.dbfファイルには通常のアルファベット文字も含まれる可能性があります。意図は、.dbfファイルからSQLiteファイルに任意のタイプのデータを投稿することです。手順以下

SQLiteのファイルにデータをポストのデータを掲載しながら、私はエラーを取得していないのですが、私はNavicatはでSQLiteのファイルを開いたとき、私は空白のレコードが表示されません。

コード

を:以下、あなたのループでは

const 
    MyDBFile = 'C:\TempDB\MYSQLightDB.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. 
+0

、なぜあなたは繰り返しCreateSQLiteTableはAdoDataSet1の行ごとに一回、呼ぶのですか?確かに一度呼び出すだけでいいですか? – MartynA

+0

この場合、はい、必要ありません。私はコードを修正しました。ありがとうございました。投稿していないデータについての推測はありますか? –

答えて

0

私はそれは問題で述べた手順を変更することによって、別の方法で解決です。データベースへの変更をコミットする前に、以下のステートメントを追加しました。

Query.ApplyUpdates(0); 

"Query.Post;"ステートメントはループ内では必要ありません。

完全な手順:あなたのConnectTodatabaseFileで

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; 
1

、あなたが挿入行ごとにQuery.Postを呼び出し、すべきであり、あなたが持っているように、私は以下のコードをしようとしています

procedure TfrmMainForm.InsertDatabtnClick(Sender: TObject); 

既にQuery.Insertと呼ばれている場合、Query.Editを呼び出す必要はありません。どのような場合でも.Editを呼び出して.Postを呼び出すと何も得られませんが、それは単なる不注意なミスか、データセットの操作方法の根本的な欠如かどうかはわかりません。これらの基本のミスと私は私のコメントで指摘1の観点

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.ExecSQLを呼び出すと、オープンのままにしないので、あなたがQuery.Closeを呼び出しておく必要はありません。

  2. while not AdoDataset1.Eofループの前に挿入SQLのパラメータ化されたバージョンをセットアップし、ループ内でのみパラメータ値を供給する方がずっと良い(SqlInjectionコンテキストでは安全です)。 QuotedStr()を使用すると、SqlInjectionポイントのためにSQLを動的に構築しないようにする必要があります。

+0

SQLiteファイルに空白のレコードがあります。 –

+1

その後、デバッグをします。 – MartynA

+0

"Query"コンポーネントを使用してデータを取得しようとすると、データ投稿後、Query.RecordCountがゼロであることが示されます。私は今見てみましょう。これは、データがまったく投稿されていないことを意味します。 –

0

以下は、私のデータを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; 
関連する問題