我在Windows 7操作系统中使用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:\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 :(得分:1)
在下面的循环中,您应该为插入的每一行调用Query.Post,并且因为您已经调用了Query.Insert,所以您不需要调用Query.Edit。在任何情况下调用.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');
鉴于这些基本错误以及我在评论中指出的错误,我认为您应该从头到尾仔细检查您的代码。
关于你自己的答案,我有几点意见:
您不需要继续调用Query.Close,因为调用Query.ExecSQL不会让它保持打开状态。
在while not AdoDataset1.Eof
循环之前设置Insert SQL的参数化版本然后仅在循环内提供参数值会更好(并且在SqlInjection上下文中更安全)。如果你这样做,你可以避免使用QuotedStr(),并且在任何情况下都应该避免因为SqlInjection点而动态构造SQL。
答案 1 :(得分: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;
答案 2 :(得分:0)
我通过修改问题中提到的过程以另一种方式解决了问题。在命名对数据库进行更改之前添加以下语句。
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;