Sqlite 有没有办法使用FireDAC插入空值作为参数?

Sqlite 有没有办法使用FireDAC插入空值作为参数?,sqlite,delphi,firedac,Sqlite,Delphi,Firedac,在表中插入值时,我希望保留一些字段为空(即Null)。我不明白为什么我想要在字段中有一个满是空字符串的DB 我使用Delphi10、FireDAC和本地SQLite数据库 编辑:提供的代码只是一个示例。在我的应用程序中,值由用户输入和函数提供,其中任何一个都是可选的。若值为空,我希望将其保持为Null或默认值。创建ExecSQL的多个变体和嵌套If语句也不是一个选项——有太多的可选字段(确切地说是18个) 测试表: CREATE TABLE "Clients" ( &

在表中插入值时,我希望保留一些字段为空(即Null)。我不明白为什么我想要在字段中有一个满是空字符串的DB

我使用Delphi10、FireDAC和本地SQLite数据库

编辑:提供的代码只是一个示例。在我的应用程序中,值由用户输入和函数提供,其中任何一个都是可选的。若值为空,我希望将其保持为Null或默认值。创建ExecSQL的多个变体和嵌套If语句也不是一个选项——有太多的可选字段(确切地说是18个)

测试表:

CREATE TABLE "Clients" (
    "Name"  TEXT,
    "Notes" TEXT
);
我就是这样尝试的:

var someName,someNote: string;
begin
{...}
someName:='Vasya';
someNote:='';
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)',
    [someName, IfThen(someNote.isEmpty, Null, somenote)]);
这引发了一个例外:

could not convert variant of type (Null) into type (OleStr)
我试图重载它并指定[ftString,ftString],但它没有帮助

目前我不得不这样做,我讨厌这种混乱的代码:

FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES ('+
    IfThen(someName.isEmpty,'NULL','"'+Sanitize(someName)+'"')+','+
    IfThen(someNote.isEmpty,'NULL','"'+Sanitize(someNote)+'"')+');');
有什么建议吗

Edit2:目前我看到一个选项,使用“INSERT或REPLACE”创建新行,然后在一行中为每个非空值使用多个更新。但这看起来非常无效。像这样:

FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name) VALUES (:nameval)',[SomeName]);
id := FDConnection1.ExecSQLScalar('SELECT FROM Clients VALUES id WHERE Name=:nameval',[SomeName]);
if not SomeString.isEmpty then
    FDConnection1.ExecSQL('UPDATE Clients SET Notes=:noteval WHERE id=:idval)',[SomeNote,id]);

根据Embarcadero文件():

要将参数值设置为Null,请指定参数数据类型, 然后调用Clear方法:

所以,我想您必须使用FDQuery来插入空值。大概是这样的:

//Assign FDConnection1 to FDQuery1's Connection property
FDQuery1.SQL.Text := 'INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)';
with FDQuery1.ParamByName('nameval') do
  begin
  DataType := ftString;
  Value := someName;
  end;
with FDQuery1.ParamByName('notesval') do
  begin
  DataType := ftString;
  if someNote.IsEmpty then
    Clear;
  else
    Value := someNote;
  end;
if not FDConnection1.Connected then
   FDConnection.Open;
FDQuery1.ExecSql;
with FDQuery1.ParamByName('name') do begin
  DataType := ftString;
  AsString := '';
  Clear;
end;
FDQuery1.ExecSQL;
不带参数以字符串形式执行查询不是一个好主意,因为这段代码容易受到SQL注入的攻击

一些消息来源说,这还不够,你应该这样做:

//Assign FDConnection1 to FDQuery1's Connection property
FDQuery1.SQL.Text := 'INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)';
with FDQuery1.ParamByName('nameval') do
  begin
  DataType := ftString;
  Value := someName;
  end;
with FDQuery1.ParamByName('notesval') do
  begin
  DataType := ftString;
  if someNote.IsEmpty then
    Clear;
  else
    Value := someNote;
  end;
if not FDConnection1.Connected then
   FDConnection.Open;
FDQuery1.ExecSql;
with FDQuery1.ParamByName('name') do begin
  DataType := ftString;
  AsString := '';
  Clear;
end;
FDQuery1.ExecSQL;

但我不能证实。如果主要示例不起作用,您可以尝试使用它。

您需要提供更多关于您试图实现的目标的解释:如果您想添加一行,并且其Notes列设置为Null,为什么不简单地从字段列表中省略Notes,即执行
插入客户机(名称)值()
?为什么要尝试插入名为coliumn设置为Null的行?变量可能是空字符串,也可能不是空字符串。我提供的代码只是一个例子,在我的实际程序中,我从窗体和各种函数的控件中收到了大约20个字段。为了清楚起见,我更新了这个问题。您真正的问题是如果函数不能处理变体。当第二个参数隐式转换为导致异常的
字符串时,使用版本形式
System.StrUtils
和传递的
Null
值。为了克服这个问题,您可以编写自己的例程,将空字符串转换为
Null
variant:
函数StrToVar(const S:string):variant;如果S=''则开始,结果:=Null,否则结果:=S;结束。你好,亚历山大。实际上,您可以让FireDAC为您处理此特定问题。您可以设置连接,以便在插入或更新数据库时将空字符串转换为NULL。看看哇,不知怎么的,我忘了你可以用FDQuery.ExecSQL来代替Open,还以为Query除了SELECT和它的变体之外,什么都不可用。你得到了一个当之无愧的好机会。请在回答中强调ExecSQL的重要性。@Alexander另一个有趣的选择是让SQLite使用
NULLIF
函数:
FDConnection1.ExecSQL('INSERT或REPLACE-INTO-Clients(Name,Notes)值(NULLIF(:nameval,'')、NULLIF(:notesval,'')、[someName,someNote])