Kori 3월 30일, 2022에 포스트됨 공유하기 3월 30일, 2022에 포스트됨 Docwiki에 있는 "Executing Commands (FireDAC)"를 번역한 글: 번역일: 2022년 3월 29일) 위로 가기: [DocWiki 번역] 명령(command)을 가지고 작업하기 (FireDAC) 목차 1 TFDConnection을 사용하기 (Using TFDConnection) 2 TFDQuery를 사용하기 (Using TFDQuery) 2.1 개발 환경에서 TFDQuery 설정하기 (Setting TFDQuery at Design Time) 2.2 파라미터 사용하기 (Using Parameters) 2.3 쿼리 준비하기 (Preparing the Query) 2.4 쿼리 실행하기 (Executing the Query) 2.5 "파라미터 데이터 타입이 변경되었습니다" 예외 ("The Parameter data type is changed" Exception) 2.6 DBMS 피드백 받기 (Getting DBMS Feedback) 3 쿼리 실행과 트랜젝션(Query Execution and Transactions) 4 고급 사용 (Advanced) 5 기타 자료 (See Also) 1 TFDConnection을 사용하기 (Using TFDConnection) TFDConnection에는 ExecSQL 메소드가 있다. 이 메소드는 간편하게 사용할 수 있고, 오버로드(overloaded)되어 있어서 다음 상황에서 유용하다. 결과 집합을 반환하지 않을 때 SQL 명령(command)을 한번만 실행하기 때문에, 준비된 상태로 저장할 필요가 없을 때 고급 파라미터 설정이 필요없을 때 디자인-타임 즉 개발 환경에서 SQL 명령(command)을 설정할 필요가 없을 때 예를 들어, DDL 명령 실행은 다음과 같이 한다. FDConnection1.ExecSQL('drop table testtab'); FDConnection1.ExecSQL('create table testtab (id integer, name varchar(10))'); FDConnection1.ExecSQL('insert into testtab values (1, ''FireDAC'')'); 파라미터를 사용하는 쿼리를 실행하려면, 오버로드된 메소드를 사용한다. FDConnection1.ExecSQL('insert into testtab values (:id, :name)', [1, 'FireDAC']); 또한, TFDConnection에는 ExecSQLScalar 메소드가 있다. 이 메소드는 ExecSQL와 달리 결과 세트 값을 1개만 반환한다. sName := FDConnection1.ExecSQLScalar('select name from testtab where id = :id', [1]); 2 TFDQuery를 사용하기 (Using TFDQuery) 대체로, TFDQuery는 디자인-타임(=개발 환경에서) 그리고/또는 런-타임(동작 중에)에 설정한다. 2.1 개발 환경에서 TFDQuery 설정하기 (Setting TFDQuery at Design Time) 디자인-타임, 즉 개발 환경에서 TFDQuery를 설정하려면, 폼 위에 TFDQuery 컴포넌트를 놓아두면 된다. 폼 위에 이미 TFDConnection가 있다면, 그것이 TFDQuery.Connection 프로퍼티에 자동으로 지정된다. 그리고 나서 TFDQuery를 더블-클릭하여 FireDAC 쿼리 에디터 창을 연다. 그림. FireDAC 쿼리 에디터 창 여기에서 SQL 문장을 명시하고, 원하는 파라미터, 매크로 값, 설정 옵션 등을 명시할 수 있다. Execute 버튼을 누르면 작성한 쿼리가 실행된다. 해당 SQL 명령이 결과 세트를 반환한다면, RecordSet 화면에 표시된다. 결과 세트의 구조는 Structure화면에 표시된다. 만약 DBMS에서 해당 명령에 대해서 메시지 또는 경고를 반환하면, Messages 화면에 표시된다. Next RecordSet 버튼을 사용하면 해당 명령에 의해 반환되는 결과 세트를 모두 둘러볼 수 있다. UPDATE/INSERT/DELETE와 같은 DML 명령(command)을 테스트할 때에는, Auto Rollback 체크 박스를 선택하여 명령이 실행된 다음 자동으로 롤백되도록 한다. OK를 눌러서 TFDQuery의 변경 사항을 저장한다. 2.2 파라미터 사용하기 (Using Parameters) "파라미터를 사용하는 쿼리 (parameterized query)"는 SQL 데이터베이스 애플리케이션을 개발할 때 실전에서 가장 유용하게 사용하는 것 중 하나이다. 주요 장점은, SQL 명령(command)을 하나만 만들고, 파라미터 값을 바꾸면서 여러번 사용할 수 있다. DBMS는 명령 실행 계획을 한번만 만든다. 따라서 DBMS의 부담이 줄어든다. 해당 SQL 명령이 다음 번에 실행될 때는 파라미터 값만 DBMS 엔진에게 전달한다. 따라서 네트워크 부담이 줄어든다. SQL 상수 형식 (constant format)을 신경쓰지 않아도 된다. 예를 들어, 마이크로소프트 Access SQL 구문에서 날짜 상수 형식을 어떻게 적는 것이 올바른 지를 몰라도 된다. 파라미터 표시자(marker)를 SQL 구문 안에 넣으려면 :<이름> 을 사용한다. 값을 넣을 때는 Params 컬렉션을 사용한다. 예를 들면, FDQuery1.SQL.Text := 'select * from tab where code = :Code'; FDQuery1.ParamByName('code').AsString := '123'; FDQuery1.Open; 쿼리를 실행하기 전에 반드시 각 파라미터의 Name, DataType, ParamType이 채워져 있어야 한다. 또한 Position도 정해져 있어야 한다. SQL 프로퍼티를 할당하고, ResourceOptions.ParamCreate가 True이면, Params 컬렉션이 자동으로 채워진다. 주의: 오직 TFDParam.Name과 TFDParam.Position만 지정된다. DataType, ParamType, 기타 프로퍼티들은 반드시 애플리케이션 안에서 지정되어야 한다. Params 컬렉션 안에 있는 파라미터들의 순서는 SQL 명령 안에 들어있는 순서와 동일하게 된다. 또한, Params 컬렉션을 코드를 이용하여 채우는 방법도 있다. 그렇게 하려면, 파라미터 자동 생성을 꺼야 하기 때문에 ResourceOptions.ParamCreate를 False로 지정한다. 예를 들면, FDQuery1.ResourceOptions.ParamCreate := False; FDQuery1.SQL.Text := 'select * from tab where code = :Code'; with FDQuery1.Params do begin Clear; with Add do begin Name := 'CODE'; DataType := ftString; Size := 10; ParamType := ptInput; end; end; SQL 명령(command)에 파라미터를 묶어줄 때는, 이름 또는 위치를 사용할 수 있다. 이것은 Params.BindMode를 통해 제어한다. pbByName: Params 컬렉션에 있는 파라미터의 Name 프로퍼티가 해당 파라미터 표시자(marker)의 이름과 같은 곳에 들어간다. 만약 SQL 명령 안에서 같은 이름을 사용하고 있는 파라미터 표시자가 있다면, Params 안에는 인스턴스가 하나만 나타난다. pbByNumber: Params 컬렉션에 있는 파라미터의 Position 프로퍼티가 SQL 명령문 안에 있는 파라미터 표시자(marker)의 순서에 맞게 들어간다. 만약 SQL 명령 안에서 같은 이름을 사용하고 있는 파라미터 표시자가 있다면, 모든 항목이 Params 안에 나타난다. Position이 파라미터에 지정되어 있지 않으면, 명령(command) 준비(prepare) 시점에 자동으로 파라미터 순번(index)에 따라 할당된다. Position은 1부터 시작한다. DataType은 명시적 또는 암묵적으로 지정된다. Value 또는 AsXxxx 프로퍼티에 값을 할당하면 된다. 할당하지 않은 경우에는, FormatOptions.DefaultParamDataType이 사용된다. ParamType이 지정되지 않으면, ResourceOptions.DefaultParamType이 사용된다. 기본 설정으로는, 모든 파라미터가 input 파라미터이다. output 파라미터를 만들려면, 반드시 DataType을 명시적으로 지정해야 된다. input 파라미터 값은 쿼리 실행 전에 반드시 지정되어야 한다. 다음 옵션 중 하나를 선택하여 진행한다. 명시적으로 파라미터 값을 할당: FDQuery1.ParamByName('code').AsString := 'DA1001'; FDQuery1.Open; 오버로딩된 ExecSQL 또는 Open 메소드 중 하나를 사용: FDQuery1.Open('', ['DA1001']); 파라미터 값에 Null을 지정하려면, 파라미터의 DataType을 명시하고 나서 Clear 메소드를 호출한다. with FDQuery1.ParamByName('name') do begin DataType := ftString; Clear; end; FDQuery1.ExecSQL; output 파라미터는 쿼리가 실행되고 난 후에야 접근할 수 있다. 일부 SQL 명령과 DBMS의 경우에는, 먼저 명령(command) 결과 세트를 모두 처리한 후에야 output 파라미터 값을 받을 수 있다. output 파라미터 값을 강제로 전달하려면 TFDAdaptedDataSet.GetResults 메소드를 사용한다. FireBird와 Oracle RETURNING 구문의 output 파라미터에 대해서는 "RETURNING Unified Support" 글을 읽어 본다. 2.3 쿼리 준비하기 (Preparing the Query) 쿼리는 실행되기 전에 반드시 준비(prepared)되어야 한다. 그러기 위해, FireDAC은 자동으로 다음 작업(action)을 수행한다. 연결(connection)을 active 또는 online 상태로 한다. 모든 파라미터가 올바르게 설정되었는지를 확인한다. 명령(command)문을 전처리한다. 필요한 경우, RecsSkip과 RecsMax를 명령(command)문에 반영한다. 필요한 경우, Firebird/Interbase DBMS 인 경우, 활성화된 연결(connection)이 없으면, 트랜젝션 하나를 시작한다. 완성된 최종 명령(command)문을 DBMS API로 전송한다. 최종 구문을 얻으려면, TFDQuery.Text 프로퍼티를 사용한다. 명령(command)이 준비되는(prepared) 동안, 연결(connection)이 반드시 활성화(active) 상태이어야 한다, 해당 쿼리는 서버 리소스를 유지한다. 쿼리 준비를 풀거나, 모든 리소스를 해제하려면, Unprepare 또는 Disconnect 메소드를 사용한다. 단 한번만 실행하면 되는 명령(command) 이라면, ResourceOptions.DirectExecute를 True로 지정한다. (MS-SQL 서버, SQL Anywhere와 같은) 몇몇 DBMS에서는, 이 방식이 실행 속도를 높인다. 그 이유는 SQL 명령(command) 준비라는 비싼 작업을 하지 않기 때문이다. 2.4 쿼리 실행하기 (Executing the Query) 결과 세트를 반환하지 않는 쿼리를 실행하려면, ExecSQL 메소드를 사용한다. 만약 결과 세트를 반환하는 쿼리인 경우 "[FireDAC][Phys][MSAcc]-310. Cannot execute command returning result sets" 예외(exception)가 발생된다. 쿼리 실행과 결과 세트 반환, 그리고 그 결과 세트 오픈(open)을 수행하려면, Open 메소드를 사용한다. 만약 결과 세트를 반환하지 않는 쿼리인 경우 "[FireDAC][Phys][MSAcc]-308. Cannot open / define command that does not return result sets" 예외(exception)가 발생된다. 애드-혹(필요할 때 바로 만들어 쓰는, ad-hoc) 쿼리를 실행하려면, ExecuteOrOpen 메소드를 사용한다. 주의: 쿼리는 비동기로 실행 될 수 있다. 만약 쿼리가 일괄 실행되는 명령 묶음인 경우, 자세한 방법은 "[DocWiki 번역] 명령 묶음 (FireDAC)"을 참고한다. 2.5 "파라미터 데이터 타입이 변경되었습니다" 예외 ("The Parameter data type is changed" Exception) 처음으로 쿼리를 Prepare/ExecSQL/Open한 후에, 쿼리에서 파라미터 타입을 바꾸면 FireDAC은 예외를 발생시킨다. [FireDAC][Phys][IB]-338. Parameter [Xxxx] data type is changed. Query must be reprepared. Prepare/ExecSQL/Open가 처음 호출될 때, FireDAC은 파라미터의 데이터 타입을 기억한다. 데이터 타입은 TFDParam.DataType 프로퍼티를 사용하여 명시적으로 지정할 수 있으며, 또는 TFDParam.AsXxxx 또는 TFDParam.Value 프로퍼티에 값을 할당하여 암묵적으로 지정할 수도 있다. 애플리케이션에서 같은 명령을 다시 실행하기 전에 파라미터의 데이터 타입을 변경한 경우, 다음번 ExecSQL/Open 호출 시, "Parameter [xxxxx] data type is changed" 예외(exception)가 발생된다. TFDParam.Value 프로퍼티는 다음 호출 시 해당 파라미터의 데이터 타입을 변경하지 않고 이미 지정되어 있는 데이터 타입으로 변환(cast)하여 값을 할당한다. 따라서 위 예외를 피하려면, 아래 중 하나를 사용한다: TFDParam.Value 프로퍼티 값. TFDParam.AsXxxx property, 이때, Xxxx는 처음 실행할 당시의 타입이어야 한다. 2.6 DBMS 피드백 받기 (Getting DBMS Feedback) TFDQuery.RowsAffected 프로퍼티를 사용하면, 명령(command)이 처리한 행(row)의 갯수를 얻을 수 있다 (예, DELETE 명령에 의해 삭제된 행의 갯수). 주의: MS-SQL 서버의 경우, 저장 프로시저 또는 테이블 트리거에 SET NOCOUNT ON이 빠져있으면 RowsAffected가 예기치 않게 -1과 같게 나올 수 있다. 이런 경우에는 TFDQuery.RecordCount 프로퍼티들 사용하여 담아온 행의 갯수를 알아낸다. 주의: FireDAC은 "N개의 행이 처리되었습니다"라는 메시지를 제공하지 않는다. 필요하다면, 이런 메시지를 직접 구축해야 한다. 만약 명령(command)이 에러를 반환하면, 예외(exception)가 발생한다. 자세한 내용은 "[DocWiki 번역] 에러 핸들링하기 (FireDAC)"를 참고한다. 예외(exception)는 다음 3가지 방법 중 하나를 사용하여 처리할 수 있다. try/except/end 구조 사용하기. 예를 들면 try FDQuery1.ExecSQL; except on E: EFDDBEngineException do ; // 여기에서 처리한다 end; TFDQuery.OnError 이벤트 핸들러 설정하기. TFDConnection.OnError 이벤트 핸들러 설정하기. 예를 들면: procedure TForm1.FDConnection1Error(ASender: TObject; const AInitiator: IFDStanObject; var AException: Exception); begin if (AException is EFDDBEngineException) and (EFDDBEngineException(AException).Kind = ekRecordLocked) then AException.Message := '잠시 후 다시 시도하세요. 해당 레코드가 사용 중입니다.'; end; FDConnection1.OnError := FDConnection1Error; Array DML에서는 에러 핸들링이 조금 더 복잡하다. 또한 명령(command)는 DBMS에 따라, warninig, hint, message를 제공한다. 메시지 처리하기를 활성화 하려면, ResourceOptions.ServerOutput을 True로 지정한다. 메시지를 처리하려면, TFDConnection.Messages 프로퍼티를 사용한다. 예를 들면, var i: Integer; begin FDConnection1.ResourceOptions.ServerOutput := True; FDQuery1.ExecSQL; if FDConnection1.Messages <> nil then for i := 0 to FDConnection1.Messages.ErrorCount - 1 do Memo1.Lines.Add(FDConnection1.Messages[i].Message); end; data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== MS-SQL 서버와 같은 몇몇 DBMS는 메시지를 추가 결과 세트 형태로 반환한다. 메시지를 처리하려면, 애플리케이션에서는 결과 세트 여러개를 처리할 필요가 있다. MS-SQL 서버의 상태와 메시지를 처리하는 더 복잡한 사례를 살펴보자. 각각 행(row)들이 담고 있는 결과 세트 여러 개를 아래와 같이 TFDMemTable을 사용하여 담는다. var i: Integer; begin FDConnection1.ResourceOptions.ServerOutput := True; FDQuery1.FetchOptions.AutoClose := False; FDQuery1.Open('select * from Region; print ''Hello'''); FDMemTable1.Data := FDQuery1.Data; Memo1.Lines.Add(Format('%d rows processed', [FDMemTable1.RecordCount])); FDQuery1.NextRecordSet; if FDConnection1.Messages <> nil then for i := 0 to FDConnection1.Messages.ErrorCount - 1 do Memo1.Lines.Add(FDConnection1.Messages[i].Message); end; data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== 3 쿼리 실행과 트랜젝션(Query Execution and Transactions) 기본 설정은 모든 SQL 명령이 자동 커밋되는 Auto Commit 모드이다. 즉, 명령(command) 실행 직전에 활성화되어 있는 트랜젝션이 없다면, 암묵적으로 트랜젝션이 시작된다. 마찬가지로 명령 실행 직후에 다음 중 하나로 끝난다. Commit: 실행이 성공한 경우 Rollback: 실패한 경우 Firebird와 Interbase에서는, 암묵적 트랜젝션이 싲가되는 시점은 쿼리 준비 전이다. 명령 하나를 실행하는 경우에 명시적으로 트랜젝션 안에 넣을 필요가 없으며, 그저 autocommit 모드를 사용하면 된다. 4 고급 사용 (Advanced) 데이터베이스 대부분에는 백-엔드 관리 도구(utility)가 제공되고 여기에서 SQL 스크립트를 실행한다. 스크립트는 DBMS의 SQL 스크립트 구문에 알맞게 여러 중릉 사용하여 작성된다. SQL 스크립트를 실행하려면 TFDScript 컴포넌트를 사용한다. 때때로, 데이터베이스 애플리케이션에서 이기종 쿼리를 서로 다른 데이터베이스에 있는 테이블을 사용하기 위해 실행하거나 또는 SQL 명렬을 데이터베이스 테이블이 아니라 TDataSet의 후손을 대상으로 실행할 수 있다. 이런 쿼리를 실행할 때에는 Local SQL 엔진과 TFDLocalSQL 컴포넌트를 사용한다. 5 기타 자료 (See Also) [DocWiki 번역] 저장 프로시저 실행하기 (FireDAC) [DocWiki 번역] 테이블 조회하기 (FireDAC) [DocWiki 번역] 명령 묶음 (FireDAC) Asynchronous Execution [DocWiki 번역] Local SQL (FireDAC) 인용하기 이 댓글 링크 다른 사이트에 공유하기 더 많은 공유 선택 사항
Recommended Posts
이 토의에 참여하세요
지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.