什么数据类型是空数据库字段?

时间:2014-08-30 18:00:54

标签: string delphi variables types null

我正在尝试计算学校项目数据库中的所有非空字段。请注意我不允许使用SQL。

这是编码

var i,k : Integer ;
begin 
  i := 0 ;
  with dmregisteredusers do
  begin
    tblusers.Sort := 'Nommer ASC';
    tblusers.Edit;
    tblusers.First;
    For k:= 1 to tblusers.RecordCount do
    begin
      If (tblusers['Dogs wanted'] = '') OR (tblusers['Dogs wanted'] = ' ') 
        OR (tblusers['Dogswanted'] = 0) 
      then 
        tblusers.Next
      else 
      begin
        inc(i);
        tblusers.Next;
      end;//else
    end;//with
  end;//for
  ShowMessage('There are ' + IntToStr(i) + ' new dogs added to wishlist ,please contact the users regarding this matter and them remove the dogs from their wishlist !');

每次运行代码时都会显示空的Db字段为数据类型为null的错误。

如何验证数据库字段为空?

2 个答案:

答案 0 :(得分:2)

这是您的代码的新版本。我完成它的方式有点乱,但我认为如果我在其中包含注释和解释的话,最容易理解。

首先要说的是,虽然检查给定行的数据集字段为Null并不是坏事,但如果不允许数据库在可能被查询的列中存储Null,通常会更好。应用程序或原始Sql查询。从理论和实践的角度来看,全书的章节都是关于Nulls做什么或不做什么的。在实践中,他们通常被认为是“信息缺失”的意思。所以我们无法回答“这个用户想要一只狗吗?”的问题。在Null的存在。所以这是一个政策和设计选择的问题,如何处理Null,但通常在数据库的实现中通过对列施加NOT NULL约束来解决问题要好得多。

当我在评论中说Delphi不是特别擅长尊重Null和空白字段之间的区别时,我的意思是:在String字段的情况下,对于字段为Null的行,Delphi当您调用Field.AsString时,返回一个空字符串''。一些“纯粹主义者”会说,如果在包含Null的情况下要求其AsXXX属性,TField应该生成异常,因为它实际上不应该尝试“伪造”某个值。它的作用,即返回一个空字符串,0表示数字字段等,这是一个实用的妥协:它避免了初学者被Nulls的存在绊倒,但如果你想让你的代码处理Null,你可以使用TField.IsNull。

如果您遇到一个包含Null的数据库 - 并且您经常会感到压抑(除非您参与了数据库的设计) - 考虑一下它们最好在SQL中处理获取数据的可能性在您的Delphi代码看到它之前。

第二件事是,在没有明确的设计简报的情况下,我们并不真正知道“想要狗”的含义。这是否意味着用户想要一个单数,复数或是/否的狗? Yes / No是最简单的处理方式,但并非所有数据库都支持显式的布尔列类型,因此您经常会看到一个(希望是单字符)CHAR,VARCHAR(或它们的Unicode等价物)列。或整数列,如果要招待挑剔的用户的要求。

第三个问题是字段的Delphi DataType不一定与db的列类型完全相同,尽管它们之间存在标准映射,无论如何,通常最好使用值表示在Delphi代码中工作(例如.AsString,.AsInteger,.AsFloat,仅举几例)与db列类型最匹配。

不可否认,并非所有的数据库实现都很繁琐,对不起,我的意思是小心,因为Delphi正在处理列的数据类型,但大多数都是。一个值得注意的例外是Sqlite,虽然您可以在表的DDL中定义列类型,但Sqlite引擎更像是推荐而不是规则,您可以在其中存储几乎任何内容。

正如我之前在评论中所说,Null是列/字段状态,而不是值。那么问“什么数据类型是一个空数据库字段?”是各种“类别错误”。列的数据类型“就像它在锡上所说的那样”,即它在表的DDL中定义的内容。当然,你真正要问的是“我如何确定该字段是否为空”,这与设计选择和数据库实现一样,与Delphi编码一样。

无论如何,足够的一般性......

procedure CountDogsWanted;
var
  // i,k : Integer ; <- names like i and k are usually as used for loop variables
  DogsWanted : Integer;
  Wanted : Boolean;
  S : String;  // contrast this naming style with what I said about the likes of i, j, k
    // I've done this because we might want to do several tests & operations on its value
    // and they will be easier to read with a shorter variable name.  Not such a good idea
    // when there are several such variables.
  AField : TField; 
const
  scDogsWanted = 'Dogs wanted';  // this is to avoid making mistakes with typos
begin

  {i := 0 ;}
  DogsWanted := 0;

  //  The point of the following line is to retrieve the field we're working with
  //  only once, rather than doing a FieldByName (which involves a serial iteration
  //  through the dataset's Fields collection) for each row in the dataset.
  //  The AField variable will remain valid for the duration of this procedure
  //  or until the dataset is closed if its Fields aren't defined as persistent ones.
  //  Persistent fields remain valid for the lifetime of their owners (usually a 
  // datamodule or form).  OTOH, "dynamic" fields are owned by the dataset and created
  // and destroyed when the dataset is opened and closed.  

  AField := dmregisteredusers.tblusers.FieldByName(scDogsWanted);

  {with dmregisteredusers do  <- Don't use "with", it only ever causes problems}
  {begin}

    {tblusers.Sort := 'Nommer ASC'; <- pointless, it makes no difference when you count what order the things are in}

    {tblusers.Edit; <- No! This puts the table into Edit state, but there's not point because you're not changing anything, and in any case, it will drop out of Edit state when you do a .Next}

    dmregisteredusers.tblusers.First;
    while not dmregisteredusers.tblusers.Eof do
    {For k:= 1 to tblusers.RecordCount do <- Never, ever, iterate a dataset with a For loop.
     The RecordCount is best avoided, too, because not all types of dataset return a meaningful
     RecordCount }

    begin
      //  You need to decide what to do about users whose 'Dogs wanted' field is Null
      //  If is is Null maybe we should ask for the record to be changed to indicate
      // explicitly whether a dog is wanted or not

      if AField.IsNull then begin
        // to be filled in by you
      end;
      //  You haven't told us what DataType the 'Dogs wanted' field is
      //  There are several possibilities.  For simplicity, let's assume that the DataType of the field is ftString
      //  Let's also make a design decision that *only* if the field only contains a 'Y' in upper or lower
      //  case, then that means a dog is wanted.
      //  First copy the field's string value into a local variable so we don't have to keep getting it for the
      //  following operation;
      S := dmregisteredusers.tblUsers.FieldByName(scDogsWanted).AsString;
      S := Trim(S);  { Trim() is a statndard function which removes leading and trailing whitespace }
      Wanted := CompareText(S, 'Y') = 0; { CompareText does a case-insensitive comparison and returns zero if equal}
      If
        { (tblusers['Dogs wanted'] = '') OR (tblusers['Dogs wanted'] = ' ')
          OR (tblusers['Dogswanted'] = 0)}
        Wanted
      then
        {tblusers.Next <- this is in the wrong place, you want to do a .Next regardless of the outcome of the "if"}
      else
      begin
        inc(DogsWanted);
        {tblusers.Next;}
      end;//else
      dmregisteredusers.tblusers.Next;
    {end;//with}
  end;//for
  ShowMessage('There are ' + IntToStr(DogsWanted) + ' new dogs added to wishlist ,please contact the users regarding this matter and them remove the dogs from their wishlist !')
end;

答案 1 :(得分:0)

我很欣赏你在答案中付出的努力我不能使用它们,因为我的导师会知道它不是我自己的工作...... @MartynA你的编码得到了我的问题的答案  这是新的编码 我知道它的草率和其他许多方法可以工作,但我真的很紧张,所以不能花时间学习代码......这是我将使用的

For k:= 1 to tblusers.RecordCount do
begin
If dmregisteredusers.tblusers.FieldByName('Dogs wanted').IsNull then tblusers.Next
else
    begin
   inc(i) ;
   tblusers.Next;
   end//then begin

我使用db form.onshow的排序,所以当DBGrid显示时它将按正确顺序...