如何将空值明确插入参数化查询中?

| 我正在使用Delphi 7和Firebird 1.5。 我在运行时创建了一个查询,其中某些值可能为null。我无法弄清楚如何使Firebird接受我需要保留为null的值的显式null。在此阶段,我正在构建SQL,以便不包含空参数,但这很乏味且容易出错。
var
  Qry: TSQLQuery;
begin
  SetConnection(Query); // sets the TSQLConnection property to a live database connection
  Query.SQL.Text := \'INSERT INTO SomeTable (ThisColumn) VALUES (:ThisValue)\';
  Query.ParamByName(\'ThisValue\').IsNull := true; // read only, true by default
  Query.ParamByName(\'ThisValue\').Clear; // does not fix the problem
  Query.ParamByName(\'ThisValue\').IsNull = true; // still true
  Query.ParamByName(\'ThisValue\').Bound := true; // does not fix the problem
  Query.ExecSQL;
当前在DB.pas中引发了EDatabaseError \“参数\'ThisValue \'\” \'的无值,因此我怀疑这是设计使然,而不是火鸟问题。 我可以将参数设置为NULL吗?如果是这样,怎么办? (编辑:抱歉,您之前没有明确尝试过.Clear。我忽略了它,只提了IsNull。添加了声明和更多代码) 抱歉,还有一件事:表上没有\“ NOT NULL \”约束。我不认为这已经走到了尽头,但我想我应该说。 完整的控制台应用程序,可在我的末端显示问题:
program InsertNull;

{$APPTYPE CONSOLE}

uses
  DB,
  SQLExpr,
  Variants,
  SysUtils;

var
  SQLConnection1: TSQLConnection;
  Query: TSQLQuery;
begin
  SQLConnection1 := TSQLConnection.Create(nil);

  with SQLConnection1 do
  begin
    Name := \'SQLConnection1\';
    DriverName := \'Interbase\';
    GetDriverFunc := \'getSQLDriverINTERBASE\';
    LibraryName := \'dbexpint.dll\';
    LoginPrompt := False;
    Params.clear;
    Params.Add(\'Database=D:\\Database\\ZMDDEV12\\clinplus\');
    Params.Add(\'RoleName=RoleName\');

    //REDACTED Params.Add(\'User_Name=\');
    //REDACTED Params.Add(\'Password=\');

    Params.Add(\'ServerCharSet=\');
    Params.Add(\'SQLDialect=1\');
    Params.Add(\'BlobSize=-1\');
    Params.Add(\'CommitRetain=False\');
    Params.Add(\'WaitOnLocks=True\');
    Params.Add(\'ErrorResourceFile=\');
    Params.Add(\'LocaleCode=0000\');
    Params.Add(\'Interbase TransIsolation=ReadCommited\');
    Params.Add(\'Trim Char=False\');
    VendorLib := \'gds32.dll\';
    Connected := True;
  end;
  SQLConnection1.Connected;
  Query := TSQLQuery.Create(nil);
  Query.SQLConnection := SQLConnection1;
  Query.Sql.Text := \'INSERT INTO crs_edocument (EDOC_ID, LINKAGE_TYPE) VALUES (999327, :ThisValue)\';
  //Query.ParamByName(\'ThisValue\').IsNull := true; // read only, true by default
//  Query.ParamByName(\'ThisValue\').Value := NULL;
  Query.ParamByName(\'ThisValue\').clear; // does not fix the problem
  Query.ParamByName(\'ThisValue\').Bound := True; // does not fix the problem
//  Query.ParamByName(\'ThisValue\').IsNull; // still true
  Query.ExecSQL;
end.
    
已邀请:
        错误的原因是\'dbx \'不知道参数的数据类型。由于从不分配任何值,因此其执行时间的数据类型为ѭ2hence,因此会出现错误。与\'ParamType \'相同,但默认情况下假定\'ptInput \',因此没有问题。
  Query.ParamByName(\'ThisValue\').DataType := ftString;
您绝对不需要
Clear
参数,因为它已经是
NULL
。我们怎么知道呢?
IsNull
返回了真相... 从TParam.Clear方法:   使用清除将NULL值分配给   参数。 从TParam.IsNull属性:   指示是否分配了值   参数为NULL(空白)。 您绝对不需要
Bound
参数,因为它完全无关紧要。如果\'Bound \'为假,则数据集将尝试从其数据源中为该参数提供默认值。但是您的数据集甚至都没有链接到数据源。从文档中:   [...]代表查询的数据集   和存储过程使用的值   一定要确定是否分配一个   参数的默认值。如果   绑定为假,数据集   表示查询尝试分配一个   数据集所指示的值   他们的DataSource属性。 [...] 如果文档不够,请参考\'sqlexpr.pas \'中的
TCustomSQLDataSet.SetParamsFromCursor
中的代码。这是在dbx框架中唯一引用参数\'Bound \'的地方。     
        使用
TParam.Clear
Query.ParamByName(\'ThisValue\').Clear;
\“使用清除为参数分配NULL值。\”(来自文档)     
        Sertac的答案是最正确的,但我也发现驱动程序的选择会有所作为。 为了他人的利益,这是一个经过改进的测试程序,该程序演示了如何使用Firebird 1.5通过参数化查询插入空值。
program InsertNull;

{$APPTYPE CONSOLE}

uses
  DB,
  SQLExpr,
  Variants,
  SysUtils;

var
  SQLConnection1: TSQLConnection;
  Query: TSQLQuery;
  A, B, C: variant;
begin
  SQLConnection1 := TSQLConnection.Create(nil);
  Query := TSQLQuery.Create(nil);

  try
    try
      with SQLConnection1 do
      begin
        Name := \'SQLConnection1\';
        DriverName := \'InterXpress for Firebird\';
        LibraryName := \'dbxup_fb.dll\';
        VendorLib := \'fbclient.dll\';
        GetDriverFunc := \'getSQLDriverFB\';
        //DriverName := \'Interbase\';
        //GetDriverFunc := \'getSQLDriverINTERBASE\';
        //LibraryName := \'dbexpint.dll\';
        LoginPrompt := False;
        Params.clear;
        Params.Add(\'Database=127.0.0.1:D:\\Database\\testdb\');
        Params.Add(\'RoleName=RoleName\');
        Params.Add(\'User_Name=SYSDBA\');
        Params.Add(\'Password=XXXXXXXXXXXX\');
        Params.Add(\'ServerCharSet=\');
        Params.Add(\'SQLDialect=1\');
        Params.Add(\'BlobSize=-1\');
        Params.Add(\'CommitRetain=False\');
        Params.Add(\'WaitOnLocks=True\');
        Params.Add(\'ErrorResourceFile=\');
        Params.Add(\'LocaleCode=0000\');
        Params.Add(\'Interbase TransIsolation=ReadCommited\');
        Params.Add(\'Trim Char=False\');
        //VendorLib := \'gds32.dll\';
        Connected := True;
      end;

      Query.SQLConnection := SQLConnection1;
      Query.SQL.Clear;
      Query.Params.Clear;
      // FYI
      // A is Firebird Varchar
      // B is Firebird Integer
      // C is Firebird Date
      Query.Sql.Add(\'INSERT INTO tableX (A, B, C) VALUES (:A, :B, :C)\');
      Query.ParamByName(\'A\').DataType := ftString;
      Query.ParamByName(\'B\').DataType := ftInteger;
      Query.ParamByName(\'C\').DataType := ftDateTime;

      A := Null;
      B := Null;
      C := Null;

      Query.ParamByName(\'A\').AsString := A;
      Query.ParamByName(\'B\').AsInteger := B;
      Query.ParamByName(\'C\').AsDateTime := C;

      Query.ExecSQL;
      writeln(\'done\');
      readln;
    except
      on E: Exception do
      begin
        writeln(E.Message);
        readln;
      end;
    end;
  finally
    Query.Free;
    SQLConnection1.Free;
  end;
end.
    
        您确定仅通过设置SQL文本即可创建参数吗? 尝试
if Query.Params.count <> 0 then
// set params
.
.
无论如何,为什么不使SQL文本:
\'INSERT INTO crs_edocument (EDOC_ID, LINKAGE_TYPE) VALUES (999327, NULL)\';
如果您知道该值将为空...     
        在ѭ14上具有一些名为HandlingStringType的属性/将空字符串转换为null。保持真实,并假设
Query.ParamByName(\'ThisValue\').AsString:=\'\'
; 您可以在
TConnection.FetchOptions.FormatOptions.StrsEmpty2Null:=True
    

要回复问题请先登录注册