2014-08-30 1 views
1

학교 프로젝트를 위해 DB의 비어 있지 않은 필드를 모두 계산하려고합니다. SQL을 사용하는 것은 허용되지 않습니다.어떤 데이터 유형이 빈 DB 필드입니까?

다음은 코딩

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) 인 것이 오류를 보여줍니다.

DB 필드가 비어있는 경우 어떻게 확인할 수 있습니까?

+0

['IsNull'] (http://docwiki.embarcadero.com/Libraries/XE6/en/Data.DB.TField.IsNull) – TLama

+0

세 번째 '개'다음에 공백이 누락 된 것처럼 보입니다. 오식? 어쨌든, "tblusers [ 'Dogs wanted'] 구조를 사용하면 필드의 내용에 변형이있는 경우 (OLH 참조) 액세스하고 있으며, 현재 이해할 수있는 깊이가 너무 멀다고 생각합니다. 현재와 ​​같은 작업으로 인해 발생할 수있는 문제. 필드에 들어가려면 tblusers.FieldByName ('Dogs wanted')을 사용하십시오. DataType 속성은 어떤 유형인지 알려줍니다. Btw, 절대 "For"루프를 사용하여 데이터 집합을 반복합니다. "동안 tblusers.Eof 할 ..."하나를 사용하십시오. 그리고 어떤 데이터베이스 유형을 사용하고 있습니까? – MartynA

+0

또한 Delphi는 데이터 세트의 주어진 열의 데이터 유형을 테이블의 각 행에 대해 동일하게 취급합니다. Null은 * 값이 아닌 * 상태 *입니다. 즉, 열 (필드)에 해당 행의 값이 없음을 의미합니다. 누구든지 프로젝트를 설정해야하고, 빈 <> NULL이라는 사실을 설명해야합니다. 그것은 중요한 차이입니다. 가운데 이름에 대한 열이 있는데 그 중 하나가없는 경우 공백 ('') 또는 NULL로 필드를 사용해야합니까? 델파이는 실제로이 차이점을 존중하는데 특히 좋지는 않지만 그것에 대해 분명히해야합니다. – MartynA

답변

2

다음은 새로운 버전의 코드입니다. 내가 해낸 방식이 조금 지저분하지만 포인트가 나오는 부분에 설명과 설명을 넣었는지 이해하는 것이 가장 쉽다고 생각했습니다.

첫 번째로 말하지만 지정된 행에 대해 Null 인 데이터 집합 필드를 확인하는 것은 좋지만 데이터베이스가 쿼리 할 수있는 열에 Null을 저장할 수 없다면 더 좋습니다. 응용 프로그램 또는 원시 SQL 쿼리에 의해. Nulls가 이론적 및 실용적인 측면에서 의미하거나하지 않는 것에 대해 전체 장을 썼습니다. 실제로, 그들은 보통 "정보 누락"을 의미하는 것으로 가장 잘 생각됩니다. 그래서 우리는 "이 사용자는 개를 원하나요?"라는 질문에 대답 할 수 없습니다. Null이있는 상태에서. 따라서 Null과 관련된 정책 및 디자인 선택의 문제이지만 열에 NOT NULL 제약 조건을 적용하여 데이터베이스 구현시 문제가 결정되는 것이 일반적으로 훨씬 낫습니다.

델파이가 Null과 빈 필드의 차이를 존중하는 데 특히 좋지 않다는 의견에 대해 말씀 드렸을 때 나는 무엇을 의미합니까? 문자열 필드의 경우 필드가 Null 인 행의 경우, Delphi는 Field.AsString을 호출 할 때 빈 문자열 ''을 반환합니다. 일부 "순정 주의자"는 Null을 포함 할 때 AsXXX 속성을 요청하면 TField에서 예외를 생성해야한다고 말합니다. 실제로 값이없는 경우 값을 "가짜"로해서는 안되기 때문입니다. 대신에 빈 문자열, 숫자 필드에 0을 반환하는 등의 작업은 약간의 실용적인 절충안입니다. 초보자가 Null이 있다는 사실을 알지 못하도록하지만, 코드에서 Null을 처리하도록하려면 다음을 수행 할 수 있습니다. TField.IsNull을 사용하십시오.

Null이 포함 된 DB에 익숙하지 않은 경우 - 자주 DB를 디자인하지 않는 한 우울하게 자주 사용됩니다. - SQL을 처리하는 데 가장 적합한 SQL 문을 사용할 가능성을 고려하십시오 귀하의 델파이 코드 전에 데이터를 볼 수 있습니다.

두 번째로 명확한 디자인 요약이 없으면 정확히 "개를 원한다"는 것을 정확히 알지 못합니다. 예를 들어 사용자가 개를 단수, 복수 또는 예/아니요 갖고 싶다는 뜻입니까? 예/아니오는 처리가 가장 간단하지만 모든 데이터베이스가 명시 적 부울 열 유형을 지원하는 것은 아니므로 자주 사용되는 (잘만하면 단일 문자) CHAR, VARCHAR (또는 해당 유니 코드 등가) 열이 대신 사용됩니다. 또는 사용자의 까다로운 요구 사항을 충족해야한다면 정수 열.

세 번째 사항은 필드의 델파이 데이터 유형이 반드시 db의 열 유형과 완전히 동일하지는 않지만 두 필드 사이에 표준 매핑이 있지만 일반적으로 값으로 델파이 코드에서 작업하는 것이 가장 좋습니다 db 컬럼 유형과 가장 잘 일치하는 표현 (예 : .AsString, .AsInteger, .AsFloat).

물론 모든 데이터베이스 구현이 까다 롭지는 않습니다. 죄송합니다. 델파이가 열의 데이터 유형을 처리하고 있지만 대부분주의해야합니다. 주목할만한 예외는 Sqlite입니다. 여기서는 테이블의 DDL에서 열 유형을 정의 할 수 있지만 Sqlite 엔진은 규칙보다 더 많은 권장 사항을 처리하므로 거의 모든 것을 저장할 수 있습니다.

앞서 언급 한 것처럼 널 (Null)은 값이 아닌 상태 인입니다. 그래서 "어떤 데이터 유형이 빈 DB 필드입니까?" 다양한 "범주 오류"입니다. 열의 데이터 유형은 "주석에서 말하는 것과 정확히 일치"합니다. 즉 테이블의 DDL에 정의 된 내용입니다. 실제로 묻고 있던 것은 "필드가 비어 있는지 어떻게 판단 할 것인가"이며 이는 델파이 코딩과 마찬가지로 설계 선택과 db 구현의 문제입니다. 일반적 충분히 어쨌든

, ...

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; 
+0

상수를 사용하는 것이 자신을 반복하는 것보다 낫지 만, 필드에 대한 참조를 보유하는 변수가 더 좋을 것입니다. – TLama

+1

@tlama : 전적으로 동의하지만, 필드 이름을 일관되게 참조하는 것이 좋고 오히려 필요한 첫 번째 단계 일 수 있는지, 특히 공백이 포함 된 필드 이름 (개인적으로는 싫어함)이있는 지점이 어둡게 보일지 궁금해 할 것입니다. 나는 다음 패스에서 그것을 할 것이다. – MartynA

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 

dbform.onshow의 정렬을 사용하여 DBGrid가 올바른 순서로 표시 될 때 ...

+0

물론, 우리 모두는 미래의 독자들에게 질문자의 즉각적인 요구처럼 많은 시간 압력, 아무런 probs 및 어쨌든 너무 일하는 것을 알고 있습니다. 하지만 제가 당신이라면, 교수자의 이마에 Null과 그로 인해 생기는 문제를 설명하고, Null이 "개가 없으면 감사함"을 의미한다고 가정합니다. 데이터가 실제로 입력 된 방식을 반영하지 않습니다. – MartynA

+0

예. 정확하게 ..사용자가 개를 요구하면 관리자는 얼마나 많은 사람들이 원하는지 알려야합니다. null이 아니면 개가 필요하다는 것을 의미합니다 ... 코드로 변환해야 할 때까지 쉽게 들립니다. 또한 코드를 사용하여 입력합니다. 데이터를 DB에 저장하면 특정 값만 필드에 표시 될 수 있습니다. –

관련 문제