Jump to content
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr ×
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr

[DocWiki 번역] 정렬, 검색, 위치 찾기, 필터링 관련 질문과 답변 (FireDAC)


Recommended Posts

Docwiki에 있는 "Sorting, Searching, Locating, Filtering Questions (FireDAC)"을 번역한 글: 번역일: 2022년 4월 18일

위로 가기: [DocWiki 번역] FAQ (FireDAC)

 

정렬, 검색, 위치 찾기, 필터링 관련 질문과 답변을 정리한 목록이다.

 

Q1: 데이터셋(dataset) 정렬이 영어가 아닌 문자열(string)에서 정확하지 않다. "[FireDAC][DatS]-2. Object [] is not found" 에러가 발생한다. 뭐가 잘못되었나?

A: 이 이슈를 교정하는 방법은 다음과 같다:

  • $(BDS)\source\data\firedac\FireDAC.inc 파일을 연다;
  • 아래 줄을 찾는다:
{$define FireDAC_NOLOCALE_DATA}   // 바이너리 데이터(data) 비교를 사용하도록 정의(define)
{$define FireDAC_NOLOCALE_META}   // 바이너리 메타데이터(metadata) 비교를 사용하도록 정의(define)
  • 주석처리하여 작동하지 않도록 한다;
  • 변경한 파일을 저장하고 애플리케이션을 다시 컴파일한다.

주의: 만약 당신의 애플리케이션에서 영어 (ASCII) 텍스트만 취급한다면, 위 줄이 주석처리되지 않도록 분명히 하라. 위 코드 줄은 정렬과 위치 찾기 동작 속도를 현격하게 높여준다

 

Q2: 데이터를 정렬하려면 인덱스(index)를 생성해야 하나?

A: 인덱스(index)를 정의할 필요가 없다. IndexFieldNames가 그 역할을 한다. 인덱스(index)를 사용하면 뷰(view)를 정의하여 필터링과 정렬을 혼합할 수 있다. indexes와 IndexDefs는 모든 FireDAC 데이터셋에서 서로 배타적이다. 즉, 당신은 indexes와 IndexDefs 중 하나만 채워야 하고 둘 다 채우면 안된다.

 

Q3: 룩업 필드(lookup field)를 인덱스(index) 정의에 사용해도 되나?

A: 안된다, 룩업 필드를 사용할 수 없다. 하지만, 인덱스(index)에 내부에서 계산되는 필드(internal calculated field)를 사용할 수 있다. 그렇게 하려면 영속 필드(persistent field)를 추가하고, fkInternalCalc 필드를 추가한 다음 OnCalcFields 이벤트 핸들러를 만들고 그 안에서 이 필드를 계산하도록 하라. 예를 들면,

 

procedure TForm21.FDTable1CalcFields(DataSet: TDataSet);
begin
  DataSet.FieldByName('f_calc').AsString :=
    FDMemTable2.Lookup('code',
      DataSet.FieldByName('f_code').AsInteger, 'name');
end;

 

 

Q4: 계산되는 필드(calculated field)를 인덱스(index) 정의에 사용해도 되나?

A: FireDAC 현재 버전에서는 FieldKind = fkCalculated 인 필드를 위치 찾기(Locate), 룩업(Lookup), IndexFieldNames 등등에서 사용할 수 없다. 해결 방법(workaround)은  fkInternalCalc 필드를 사용하는 것이다. 

 

Q5: 실행 중에 FindNearest 메소드를 호출하면,  활성화된(active) 인덱스가 없다는 내용으로 시작하는 에러 메시지가 나온다.

A: 인덱스(index)를 활성화(active) 해야할 뿐만 아니라 그 인덱스를 선택해야만 한다. 그렇게 하려면: 

  • Indexes[i].Selected := True로 지정한다.
  • 또는 FDTable1.IndexFieldName := <당신의 인덱스 이름>으로 지정한다.

 

Q6: TADDataset 인덱싱을 하기 위해 서로 다른 character collation(문자 비교 규칙 세트)을 정의하는 방법

A: 대체로, 3가지 선택이 있다:

  • TFDMemTable.Table.Locale에 LCID를 할당(assign)한다. FireDAC은 CompareStringA와 CompareStringW를 SORT_STRINGSORT 플래그와 함께 사용한다. collation(문자 비교 규칙 세트)는 기본 설정에서 "DBMS 독립적"이다. 즉, LOCALE_USER_DEFAULT이다. 자세한 내용은 Win API 도움말 참고.
  • FireDAC.DatS.pas 소스 코드를 변경한다. TFDDatSRow.CompareData를 찾아서 당신 만의 비교 알고리즘을 구현한다.
  • 표현식 평가기(expression evaluator)를 가지는 맞춤 함수를 등록한다. 등록하는 자세한 방법은 FireDAC.Stan.Expr.pas 을 참고한다. 그리고 나서 이 함수를 TFDMemTable.Indexes[..].Expression에서 사용한다. 예를 들면: Expression := 'MySort(Name)'.

앞으로, 맞춤 collation을 구현하려고 한다. 그러면 당신처럼 SQLite 드라이버를 사용하는 경우 도움이 될 것이다.

 

Q7: COL1 descending(내림차순), COL2 ascending(올림차순) 처럼 데이터를 정렬하는 방법은?

AIndexFieldNames := 'col_1:D;col_2'; 

 

Q8: FDQuery.Locate를 MS-SQL 서버에서 사용하는데 "Function sequence error" 에러가 난다. 뭐가 잘못되었나?

A: 명시적인 트랜젝션이 시작된 후에 FDQuery가 오픈(open)된 것으로 보인다. 그 후에 트랜젝션이 커밋(commit)되고, 다시 그 후에 FDQuery.Locate를 호출하였는데 FDQuery가 모든 레코드를 가져오지 않았고 그 대신 Locate 메소드에 의해 암묵적으로 FetchAll이 호출되었을 것이다. 이상이 이 에러가 SQL 서버에서 발생하는 이유이다.

 

피하는 방법은 다음과 같다:

SQL 서버는 Commit/Rollback을 한 후에는 오픈(open)된 커서(cursor)를 무효화 한다.

 

Q9: 룩업(Lookup) 테이블을 구현하는 가장 좋은 방법은 무엇인가? 오픈(open)/로드(load) 가 느린걸로 봐서 룩업 테이블이 너무 큰것 같다.

A: 클라이언트에서 모든 레코드가 필요한 것이 아니라면 이 구문을 사용하라. TFDQuery with SELECT ... WHERE .... 

 

Q10: 최상의 성능을 낼 수 있도록 하려면 룩업(Lookup) 필드를 어떻게 다루면 좋은 지 힌트를 줄 수 있나?

A: TFDQuery.IndexFieldNames에 LookupKeyFields를 지정하라, 그러면 FireDAC은 클라이언트 인덱스를 사용하여 룩업 데이터셋(Lookup dataset) 안에서 레코드의 위치를 찾는다.

만약, 고유(unique) 키 값이 너무 높지 않다면, LookupCache에 True를 지정하라.

 

 

Q11: DateTime 값으로 필터링을 하려는데 잘 안된다. 뭐가 잘못되었나?

Q: Delphi 2007에서 FireDAC 2.0.11.895을 사용하여 Postgres 데이터베이스를 다루고 있다. DateTime 필드를 기분으로 필터링을 하려고 하는데, 아래와 같은 값을 전달하면 정확히 일치하는 것을 가져오지 못하는 것 같다: 

created_date = '8/10/2009 14:42:14'         // 또는 심지어...
created_date = '8/10/2009 14:42:14.247'     // ... 밀리초(millisec)까지 일치해야 하는 상황

그래서 결국 아래와 같이 작성해야 했다: 

created_date >= '8/10/2009 14:42:14' AND created_date < '8/10/2009 14:42:15' // 또는
created_date >= '8/10/2009 14:42:14.000' AND created_date <= '8/10/2009 14:42:14.999'

A: 이 문제는 DBMS 또는 DBMS API 에서 시간 값을 반올림하기 때문일 것이다. 프로그래머는 소숫점 이하에 .247를 기대하지만, 이 값이 .246 이거나 다른 값일 수있다. 이것은 FireDAC이 실패한 것이 아니라 DBMS가 어떻게 작동하느냐에 따라 결정되는 것이다.

당신은 시간 값을 초단위로 반올림하고 그 값을 소숫점 이하가 없는 상수(constant) 값과 비교할 수 있다: 

uses
  FireDAC.Stan.ExprFuncs;
...
  FDQuery1.Filter = 'TimeStampDiff(''second'', created_date,
    convert(''timestamp'', ''8/10/2009 14:42:14'')) = 0';

 

이 댓글 링크
다른 사이트에 공유하기

이 토의에 참여하세요

지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.

Guest
이 토픽(기고/질문)에 답하기

×   서식있는 텍스트로 붙여넣기.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   이전에 작성한 콘텐츠가 복원되었습니다..   편집창 비우기

×   You cannot paste images directly. Upload or insert images from URL.

 공유하기

×
×
  • Create New...

중요한 정보

이용약관 개인정보보호정책 이용규칙 이 사이트가 더 잘 작동하기 위해 방문자의 컴퓨터에 쿠키가 배치됩니다. 쿠키 설정 변경에서 원하는 설정을 할 수 있습니다. 변경하지 않으면 쿠키를 허용하는 것으로 이해합니다.