如何检查单行中是否为空值

时间:2014-01-11 00:49:35

标签: delphi delphi-xe2 ado

我从db获取值,当值 NULL 时出现错误

  

无法将类型(null)的变体转换为类型(整数)

如果我使用 0 填充数据库而不是任何内容( NULL ),则错误消失

所以说我有这个

  OneSpell.PerCent     :=              FQuery.Recordset.Fields[ DB_FLD_PER_CENT    ].Value;
  OneSpell.Plus        := TCardPlus  ( FQuery.Recordset.Fields[ DB_FLD_PLUS        ].Value );
  OneSpell.Quantity    :=              FQuery.Recordset.Fields[ DB_FLD_QUANTITY    ].Value;

有没有办法说明值是 NULL 然后使其 0 ?或者这必须通过数据库完成。

FQueryadoquery,db是访问

我知道我能做到

if  .... = null then 
  onespell.plus := 0 
else
   .........

但我想在onepell

的每个值的一行中做到这一点

6 个答案:

答案 0 :(得分:8)

这是常见的方法:

提取重复部分以保持代码DRY并提高可读性

function IfNull( const Value, Default : OleVariant ) : OleVariant;
begin
  if Value = NULL then
    Result := Default
  else
    Result := Value;
end;

...
OneSpell.Plus := IfNull( FQuery.Recordset.Fields[ DB_FLD_PER_CENT].Value, 0 );

答案 1 :(得分:6)

因为您正在使用ADOQuery.Recordset,它返回对底层_Recordset的引用(不是来自Delphi,而是直接是ADO对象引用),您的选择仅限于那些ADO直接支持。 Delphi的TADOQuery具有包装方法,可以隐藏在较低级别处理ADO的大量复杂性,而使用Recordset会严重限制您的选项。

AFAICT,在一行中执行此操作的唯一方法是使用长行,它同时使用VarIsNull函数和Math.IfThen函数(默认为{如果省略0参数,则{1}}:

AFalse

您可以使用中间OneSpell.PerCent := IfThen(not VarIsNull(FQuery.Recordset.Fields[ DB_FLD_PER_CENT].Value), FQuery.Recordset.Fields[DB_FLD_PER_CENT].Value); 变量(仍然需要OleVariant单位)更可读地使用两行:

Math

最简单的替代方法(无论如何,从Delphi代码的角度来看)将在SQL语句本身中使用var Val: OleVariant; ... Val := FQuery.Recordset.Fields[DB_FLD_PER_CENT].Value; OneSpell.PerCent := IfThen(not VarIsNull(Val), Val); IsNull或其在MS Access中的等价物处理此问题,因此您不需要不得不在你的应用程序代码中担心它;你可以简单地访问Coalesce并知道它包含一个整数。

实际上,最简单替代方法是,如果您实际上不需要这样做,则根本不使用Value(因为RecordSet结果中有多个记录集)。如果您只是直接使用Delphi的TADOCommand,您只需使用原生TADOQuery属性,它将自动为您处理转换:

TField.AsXXX

答案 2 :(得分:4)

停止在delphi代码中工作,你的查询应该处理这个问题。大多数数据库后端支持COALESCE功能。因此,在您的查询中,只需使用:SELECT COALESCE(MyIntegerField, 0) FROM Foo。如果MyIntegerField包含NULL值,COALESCE将返回第一个non-NULL值,在这种情况下为0

修改

刚刚意识到您的数据库后端是MS Access,在这种情况下使用IIF函数:

SELECT Percent= IIf([Percent] Is Null, 0, [Percent]) FROM Foo

答案 3 :(得分:2)

如果您知道您总是希望将Null解释为false布尔值,0数值或空字符串,则可以设置System.Variants.NullStrictConvert = false。

(严格地说,对于Null到字符串转换,将采用System.Variants.NullAsStringValue的值。)

答案 4 :(得分:2)

会尝试展示另外两种变体,这些变体在开箱即用。

1:使用TDataSet原生访问

OneSpell.Plus := TCardPlus  ( FQuery.FieldByName( 'DB_FLD_PLUS' ).AsInteger ); 

OneSpell.Plus := TCardPlus  ( FQuery.Fields[ 2 ].AsInteger ); 

假设“DB_FLD_PLUS”是查询中的第三列。对于空(NULL)列,TField.AsInteger返回零。

2:使用Delphi高级记录

type 
   TSpellPlus = record
       Value : TCardPlus;
       class operator Implicit( const from: TCardPlus ):  TSpellPlus; inline;
       class operator Implicit( const from: Variant ):    TSpellPlus;
       class operator Implicit( const from: TSpellPlus ): TCardPlus;  inline;
   end;

   TOneSpell = record
     private
       function GetCardPlus: TCardPlus; inline;
       procedure SetCardPlus( const Value: TCardPlus ); inline;
     public   
       var PerCent : integer;  
       var PlusVar : TSpellPlus;
       property Plus : TCardPlus read GetCardPlus write SetCardPlus;
       var Quantity : cardinal;
   end;

 function TOneSpell.GetCardPlus: TCardPlus;
 begin
    Result := Self.PlusVar;
 end;

 procedure TOneSpell.SetCardPlus( const Value: TCardPlus );
 begin
    Self.PlusVar := Value;
 end;

 class operator TSpellPlus.Implicit( const from: TSpellPlus ): TCardPlus;
 begin
    Result := From.Value; 
 end;

 class operator TSpellPlus.Implicit( const from: TCardPlus ):  TSpellPlus;
 begin
    Result.Value := From;
 end;

 class operator TSpellPlus.Implicit( const from: Variant ):    TSpellPlus;
 var i: integer;
 begin
    if VarIsNull( From )
       then i := 0 
       else i := From;
    Result.Value := TCardPlus( i );
 end;


   ....

 OneSpell.PlusVar := FQuery.Recordset.Fields[ DB_FLD_PLUS        ].Value; 

然后这三行是等价的:

var cp: TCardPlus;

cp := OneSpell.Plus;
cp := OneSpell.PlusVar;
cp := OneSpell.PlusVar.Value;

答案 5 :(得分:0)

有趣的帖子和有趣的答案,无论如何,没有提到的内容,至少在所有答案中都很清楚,并且可能看起来非常明显,但对于 Delphi/Firedac 的新手来说,您需要包括的不是那么多(添加到模块的使用)接口 SYSTEM.VARIANTS 以询问 datafield.value = NULL 或 <> NULL。