배열 변수
배열 변수의 기본 개념과 선언 방법, 그리고 배열 변수를 tbESQL/COBOL 문장에서 입/출력 변수로 사용하는 방법을 설명합니다.
개요
tbESQL/COBOL 프로그램의 배열 변수는 COBOL 프로그래밍 언어의 배열 변수의 개념과 동일합다. 배열 은 동일한 타입의 값을 여러 개 저장할 수 있는 데이터 구조입니다.
tbESQL/COBOL 프로그램에서는 SELECT 문장을 실행한 뒤 다수의 결과 로우를 저장하기 위해서 출력 변수로 배열 변수를 사용하거나, INSERT 문장을 사용할 때도 보통 여러 개의 로우를 삽입하게 되므로 입 력 변수로 배열 변수를 사용합니다.
배열 변수가 출력 변수로 사용될 때는 출력 배열 변수라고 부르며, 입력 변수로 사용될 때는 입력 배열 변 수라고 합니다. 출력 배열 변수와 입력 배열 변수가 사용되는 문장은 다음과 같습니다.
출력 배열 변수
SELECT
입력 배열 변수
INSERT
UPDATE
DELETE
tbESQL/COBOL 프로그램에서 tbESQL/COBOL 문장과 COBOL 프로그램의 변수 사이에 데이터를 주고 받을 때 배열 변수를 사용하면 다음과 같은 장점이 있습니다.
간결하고 구조적인 프로그래밍 배열 변수를 사용하면 각각의 로우를 처리할 때마다 별도의 SQL 문장을 사용하지 않고, 모든 로우를 하 나의 SQL 문장으로 처리할 수 있습니다. 따라서 프로그램의 소스 코드를 보다 단순화할 수 있으며, 구조적 인 프로그래밍이 가능합니다.
tbESQL/COBOL 프로그램의 성능 향상 클라이언트와 서버 환경에서는 데이터를 주고 받기 위하여 많은 시간이 필요합니다. 배열 변수를 사용해 여러 로우를 한꺼번에 처리하면 전송 시간이 크게 줄어듭니다.
배열 변수 선언
tbESQL/COBOL 문장에서 사용될 배열 변수는 대체로 COBOL 프로그램에서 배열 변수를 선언하는 방법 과 같습니다. 다만, tbESQL/COBOL 문장에 사용될 배열 변수를 선언할 때에는 반드시 DECLARE 영역 안에 선언해야 합니다.
다음은 배열 변수를 선언하는 예입니다.
입/출력 배열 변수
본 절에서는 tbESQL/COBOL 문장에서 배열 변수가 입/출력 변수로 사용될 경우 각 tbESQL/COBOL 문장 에 따른 배열 변수의 사용 방법에 대해 설명합니다.
SELECT
SELECT 문장을 실행하여 반환되는 결과 로우의 개수가 하나 이상이라면 반드시 커서 또는 배열 변수를 사용해야 합니다. 결과 로우의 개수를 미리 예측할 수 있습니다면 배열 변수의 크기를 충분히 선언하여 사용할 수 있습니다. 만약 결과 로우의 개수가 예측하기 힘들거나 매우 크다면, 배열 변수와 커서를 함께 사용할 수도 있습니다.
배열 변수
SELECT 문장의 실행 결과로 반환된 로우의 개수가 예측 가능하고 크기가 크지 않다면 배열 변수를 이용 하여 모든 결과 로우를 한번에 받을 수 있습니다. 예를 들어 SELECT 문장의 결과로 반환되는 로우의 개수가 50개를 넘지 않는 경우에 다음과 같이 소스 코드를 작성할 수 있습니다.
[예 1] SELECT 문장에서의 배열 변수의 사용
결과 로우의 각 컬럼 값은 각 배열 변수에 저장되며, 저장될 때 같은 순서의 변수에 저장됩니다. 예를 들어 세 번째 로우의 컬럼 값은 각각 배열 변수의 세 번째 위치인 ENAME(3), SALARY(3), ADDR(3)에 저장됩니다.
SELECT 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
INTO 절에 포함되는 출력 변수는 배열 변수와 일반 변수가 동시에 함께 올 수 없습니다. 따라서 INTO 절에 포함된 모든 출력 변수는 배열 변수이거나 또는 일반 변수이어야 합니다.
SELECT 문장의 실행 결과로 반환된 로우의 전부가 아닌 일부만을 얻고 싶을 때에도 배열 변수를 이용 할 수 있습니다. 위의 [예 1]에서 SELECT 문장의 실행 결과로 반환된 로우가 50개가 넘는 경우에 50개까 지의 결과 로우만을 배열 변수에 저장합니다.
SELECT 문장의 실행 결과로 배열 변수에 저장된 로우의 실제 개수는 변수인 SQLERRD(3) IN SQLCA를 통해 알 수 있습니다. 다음은 SELECT 문의 실행 후에 올 수 있는 소스 코드에 SQLERRD(3) IN SQLCA를 사용한 예입니다.
맨 마지막 라인을 보면 반환된 로우의 개수를 출력하는 데 SQLERRD(3) IN SQLCA를 사용하였습니다.
배열 변수의 크기가 일정하지 않은 경우에는 가장 작은 배열 변수의 크기를 전체 배열 변수의 크기로 설 정합니다. 예를 들어 다음의 소스 코드와 같이 배열 변수가 선언된 경우에 배열 변수 ENAME과 SALARY 의 크기는 50이지만, ADDR의 크기가 30이므로, SELECT 문의 실행 후에 반환되는 결과 로우의 개수는 30개입니다.
SELECT 문장의 WHERE 절에는 배열 변수가 올 수 없습니다. WHERE 절에 배열 변수가 오는 경우 질의의 의미가 모호해지기 때문입니다.
따라서 다음과 같은 소스 코드는 프리컴파일 과정에서 에러를 반환합니다.
배열 변수와 함께 커서를 사용하더라도 SELECT 문장의 WHERE 절에 배열 변수를 사용할 수는 없습니다.
배열 변수와 커서
SELECT 문장의 실행 결과로 반환되는 로우의 개수를 예측하기 어렵거나 반환되는 로우의 개수가 많다 면 배열 변수와 함께 커서를 이용하여야 합니다. 이때 일반 커서는 물론 스크롤 가능 커서도 사용할 수 있습니다.
커서와 배열 변수를 함께 사용하는 방법은 커서와 일반 변수를 함께 사용하는 경우와 거의 유사합니다. 하지 만 FETCH를 실행할 때 루프를 빠져 나오는 방법이 일반 변수를 사용할 때와 다릅니다. 그 이유는 NOT FOUND 에러가 발생되는 경우가 차이가 있기 때문입니다.
일반적으로 커서를 이용하여 루프 내에서 결과 로우를 액세스할 때 더 이상 읽어 올 결과 로우가 없으면 NOT FOUND 에러가 반환됩니다. 하지만 일반 변수일 때와 배열 변수일 때 NOT FOUND 에러는 다음과 같 은 차이가 있습니다.
일반 변수
일반 변수를 이용할 때에는 결과 로우를 하나씩 액세스하므로 NOT FOUND 에러가 발생할 때에는 출력 변수에 저장된 결과 로우는 없음
배열 변수
배열 변수를 이용할 때에는 배열 변수의 크기보다 작은 수의 결과 로우를 반환하더라 도 NOT FOUND 에러를 반환
즉, NOT FOUND 에러를 반환하더라도 출력 배열 변수에는 결과 로우가 포함되어 있을 수 있음
따라서 배열 변수를 사용할 때는 SQLCA의 변수를 사용해 루프를 빠져 나온다. 커서와 함께 배열 변수가 사용될 때에 SQLERRD(3) IN SQLCA에는 FETCH 문장을 수행할 때마다 현재까지 처리된 결과 로우의 누적 개수가 저장됩니다. 그러므로 이 누적 개수가 더 이상 증가하지 않을 때 루프를 중단하면 됩니다.
다음은 루프를 중단하는 소스 코드의 예입니다.
[예 2] SQLERRD(3) IN SQLCA를 활용한 루프의 중단
위의 예에서는 두 개의 새로운 변수 BEFORE-COUNT와 CURRENT-COUNT를 사용하여 두 변수의 값이 일치하면 FETCH 루프를 중단합니다. 출력 배열 변수에 저장된 실제 결과 로우의 개수는 변수 COUNT에 저 장됩니다.
다수의 커서
SELECT 문장에는 배열 변수와 함께 다수의 커서를 사용할 수도 있습니다. 몇 개의 커서를 사용하더라도 하나 의 커서를 사용할 때와 동일하게 처리됩니다. 동시에 여러 개의 커서를 사용할 때 SQLCA의 변수는 각 커서 마다 별도로 선언되지는 않습니다. 따라서 변수 SQLCA에 저장된 데이터는 직전에 실행된 질의 또는 기타 SQL 문장의 결과에 대한 데이터입니다.
다음은 각 커서에 FETCH를 수행할 때마다 변수 SQLCA에 저장되는 데이터의 예입니다.
위의 예에서 배열 변수 ENAME과 SALARY는 각각 크기가 20과 30이며, 커서 CUR1과 CUR2에 연관된SELECT 문장의 결과 로우의 개수가 충분히 크다고 가정합니다.
스크롤 가능 커서
SELECT 문장에는 배열 변수와 함께 스크롤 가능 커서를 사용할 수도 있습니다. 스크롤 가능 커서는 일반 커 서의 경우와 거의 동일하게 사용할 수 있으나, SQLERRD(3) IN SQLCA에 저장되는 값의 의미가 달라진 다.
일반 커서와 스크롤 가능 커서의 SQLERRD(3) IN SQLCA 값의 차이는 다음과 같습니다.
일반 커서의 SQLERRD(3) IN SQLCA
일반 커서의 경우에는 액세스된 결과 로우의 누적 개수를 저장하고 있음
스크롤 가능 커서의 SQLERRD(3) IN SQLCA
현재까지 액세스된 가장 마지막 결과 로우의 절대 위치를 저장하고 있음
스크롤 가능 커서를 사용할 때 SQLERRD(3) IN SQLCA에 저장되는 값은 다음과 같이 결정됩니다.
FETCH 문장을 수행할 때마다 옵션에 의하여 정해진 결과 로우의 위치로부터 배열 변수의 크기만큼 액세 스하게 되므로, SQLERRD(3) IN SQLCA에 저장되는 값은(액세스하고자 하는 결과 로우의 절대 위치 + 배 열 변수의 크기 - 1) 값 중에서 현재까지 가장 큰 값이 됩니다. 만약 액세스하려는 위치에서부터 남아 있는 결 과 로우의 개수가 배열 변수의 크기보다 작다면 SQLERRD(3) IN SQLCA에 저장되는 값은 전체 결과 로 우의 개수가 됩니다. 결과 로우의 절대 위치 값과 SQLERRD(3) IN SQLCA 값은 항상 1 이상입니다.
다음의 소스 코드는 배열 변수와 함께 스크롤 가능 커서를 사용하는 예입니다.
위의 예에서 배열 변수 ENAME의 크기는 20이며, 커서 CUR에 연관된 SELECT 문장의 결과로 반환된 로 우의 전체 개수는 90이라고 가정합니다.
지시자 배열 변수
SELECT 문장에는 출력 배열 변수와 함께 지시자 배열 변수를 사용할 수 있습니다.
지시자 배열 변수는 출력 배열 변수와 같은 크기를 가져야 하며, 배열 변수로 선언합니다는 것 외에는 일반 적인 지시자 변수와 동일하게 사용할 수 있습니다. 반환되는 컬럼 값이 NULL이거나 값의 일부가 잘릴 가능성 이 있습니다면 지시자 배열 변수의 사용을 고려해야 합니다. 지시자 배열 변수도 다른 변수와 마찬가지로 DECLARE 영역 내에 선언합니다.
다음은 지시자 배열 변수를 사용한 예입니다.
참고
입력 배열 변수와 함께 지시자 배열 변수를 사용할 수도 있습니다. 입력 지시자 변수는 INSERT, UPDATE, DELETE 문장에서 사용할 수 있습니다.
사용 예제
다음은 [예 11]에서 제시한 예제를 배열 변수를 이용하도록 수정한 예입니다.
① [예 11]과 비교했을 때 변수를 배열 변수로 선언합니다.
② FETCH를 수행할 때 루프를 중단합니다.
③ 배열 변수에 저장된 컬럼의 값을 DISPLAY 문을 통해 출력합니다.
INSERT
INSERT 문장에서 배열 변수를 사용하는 방법은 일반적인 입력 변수를 사용하는 방법과 동일합니다. 입력 배열 변수가 사용되는 각 문장은 문장이 실행되기 직전에 동적으로 배열 변수에 저장된 값을 읽어 들인다. 따라서 각 문장이 실행되기 전에 반드시 배열 변수에 적절한 값을 넣어 주는 코드가 있어야 합니다.
INSERT 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
INSERT 문장에서 사용되는 입력 변수는 배열 변수와 일반 변수가 함께 올 수 없습니다. 따라서 모든 입력 변수가 배열 변수이거나 일반 변수로만 구성되어야 합니다.
SELECT 문장과 유사하게 SQLERRD(3) IN SQLCA에는 삽입된 로우의 개수가 저장되어 있습니다. SQLERRD(3) IN SQLCA에는 항상 하나의 INSERT 문장에 의해 삽입된 로우의 개수만 저장됩니다.
FOR 절을 사용해 입력 배열 변수의 크기보다 적은 개수의 로우를 삽입하도록 할 수도 있습니다. 예를 들면 크기가 50인 입력 배열 변수의 내용 중에서 30개의 로우 값만을 이용하는 경우입니다.
입력 배열 변수와 함께 지시자 배열 변수를 사용할 수도 있습니다. 삽입해야 할 컬럼 값 중 일부만 NULL 값 인 경우에는 반드시 지시자 배열 변수를 사용해야 합니다.
다음은 배열 변수와 함께 INSERT 문장을 실행하는 예입니다.
[예 3] INSERT 문장의 배열 변수
위의 [예 3]에서의 INSERT 문장은 다음의 루프를 이용한 소스 코드와 같은 결과를 갖습니다. 하지만 배열 변수를 이용하는 편이 서버와의 통신 비용을 크게 줄일 수 있으므로 성능 면에서 훨씬 효율적입니다.
다음은 컬럼 SALARY에 대해 지시자 배열 변수를 사용한 예입니다.
UPDATE
UPDATE 문장에서 배열 변수를 사용하는 방법도 일반 변수를 사용하는 방법과 유사합니다.
UPDATE 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
UPDATE 문장에서는 SELECT 문장과는 다르게 WHERE 절에도 배열 변수를 사용할 수 있습니다. WHERE 절에 배열 변수를 사용하면 SET 절에도 배열 변수를 사용해야 합니다. 만약 WHERE 절에 일반 변수를 사용하였습니다면 SET 절에도 일반 변수를 사용하여야 합니다.
INSERT 문장과 유사하게 SQLERRD(3) IN SQLCA에는 갱신된 로우의 개수가 저장됩니다. SQLERRD(3) IN SQLCA에는 항상 하나의 UPDATE 문장에 의해 갱신된 로우의 개수만 저장되며, 무결성 제약조건을 만족하기 위해 연속적으로 갱신되거나 삭제된 로우의 개수는 포함되지 않습니다.
UPDATE 문장에서 SET 절 내에 사용된 입력 변수에는 배열 변수와 일반 변수가 함께 올 수 없습니다.
SELECT FOR UPDATE 문장 내에서 UPDATE ... CURRENT OF 절과 함께 배열 변수를 사용할 수 없습니다.
다음은 UPDATE 문장의 SET 절과 WHERE 절에 배열 변수를 사용한 예입니다.
[예 4] UPDATE 문장의 배열 변수
위의 [예 4]은 다음과 같은 루프를 이용한 연속된 UPDATE 문장과 동일한 결과를 갖습니다. 하지만 배열 변수를 이용하는 편이 성능 면에서 더욱 효율적입니다.
DELETE
DELETE 문장에서 배열 변수를 사용하는 방법도 일반 변수를 사용하는 방법과 유사합니다.
DELETE 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
DELETE 문장에서도 UPDATE 문장과 같이 WHERE 절에 배열 변수를 사용할 수 있습니다.
INSERT, UPDATE 문장에서와 유사하게, SQLERRD(3) IN SQLCA에는 삭제된 로우의 개수가 저장됩니다. SQLERRD(3) IN SQLCA에는 항상 하나의 DELETE 문장에 의하여 삭제된 로우의 개수만 저장되며, 무결성 제약조건을 만족하기 위하여 연속적으로 갱신되거나 삭제된 로우의 개수는 포함되지 않습니다.
DELETE 문장의 WHERE 절에 사용될 입력 변수로 배열 변수와 일반 변수가 함께 올 수 없습니다.
DELETE 문장에 배열 변수를 사용할 때는 DELETE ... CURRENT OF 절을 사용할 수 없습니다.
다음은 DELETE 문장의 WHERE 절에 배열 변수를 사용한 예입니다.
[예 5] DELETE 문장의 배열 변수
위의 [예 5]은 다음의 루프와 동일한 결과를 갖습니다. 하지만 INSERT, UPDATE 문장과 마찬가지로 배열 변수를 이용하는 편이 성능 면에서 효율적입니다.
FOR 절
INSERT, DELETE, UPDATE 문장에서 입력 배열 변수를 사용할 때 배열 변수의 크기보다 적은 개수의 로 우를 처리하려는 경우에 FOR 절을 사용합니다. FOR 절은 EXEC SQL 바로 다음에 오며, 처리하고자 하는 로우의 개수를 명시합니다.
FOR 절에 로우의 개수를 명시할 때 다음의 사항에 유의해야 합니다.
FOR 절에 로우의 개수를 명시할 때는 숫자를 명시할 수도 있으며, 변수를 명시할 수도 있습니다. 변수를 명시할 경우 해당 변수는 반드시 DECLARE 영역에 선언되어 있어야 합니다.
FOR 절에 로우의 개수를 명시할 때 연산식을 사용해서는 안 됩니다.
FOR 절의 로우 개수는 항상 입력 배열 변수의 크기보다 작아야 합니다.
tbESQL/COBOL 프로그램에서는 지정된 로우의 개수를 저장할 배열 변수의 크기를 검토하지 않습니다.
만약 지정된 로우의 개수보다 배열 변수의 크기가 작다면, 내부적으로 유효하지 않은 메모리에 접근하게 되어 메모리 에러가 발생하고, 이때 tbESQL/COBOL 프로그램이 어떠한 동작을 할지 보장할 수 없 다.
다음의 소스 코드는 FOR 절을 이용하는 예입니다.
① 로우의 개수를 숫자로 설정하여 FOR 절을 이용할 수 있습니다.
② 변수를 이용하여 로우의 개수를 설정하여 FOR 절을 이용할 수 있습니다. 단, 변수 ROW-COUNT는 DECLARE
영역에 선언되어 있어야 합니다.
다음은 FOR 절에서 로우의 개수를 명시할 때 임의의 연산식을 사용한 경우로 잘못된 예입니다.
구조체 배열 변수
tbESQL/COBOL 문장 내에서 여러 컬럼을 동시에 처리할 때 각 컬럼별 입/출력 변수 각각을 나열할 수도 있지만, 각 컬럼에 대한 변수를 모아 하나의 구조체로 정의하여 구조체 타입의 변수를 이용할 수도 있습니다.
또한 더 나아가 각 컬럼의 여러 로우를 한꺼번에 처리하고자 할 때 구조체로 정의한 타입을 배열로 선언하 여, 구조체 배열 변수를 이용할 수 있습니다.
구조체 배열 변수의 선언
구조체 배열 변수를 선언할 때는 다음의 사항에 유의해야 합니다.
구조체 배열 변수는 반드시 DECLARE 영역에 선언되어야 합니다.
tbESQL/COBOL 문장에서 사용되는 구조체 타입의 변수는 중첩되어 정의될 수 없습니다(일반적인 구조체 변수일 때나 구조체 배열 변수일 때나 동일합니다).
구조체 변수의 그 하위 멤버는 배열일 수 없습니다(일반적인 구조체 변수일 때나 구조체 배열 변수일 때나 동일합니다).
다음은 구조체 배열 변수를 선언하는 예입니다.
다음은 구조체를 잘못 선언한 예입니다.
위의 예에서는 구조체 EMP 내부에 구조체 SUB_EMP를 중첩하여 정의하였습니다. 구조체 타입의 변수는 중 첩되어 정의될 수 없습니다.
다음은 구조체 타입 변수의 하위 멤버를 배열로 선언한 경우로 잘못 선언한 예입니다.
위의 예에서 ENAME과 ENAME-ARR의 하위 멤버로 각각 배열을 선언하였습니다. 구조체 타입의 변수는 하위 멤버로 배열이 올 수 없습니다.
사용 방법
단순 구조체 타입의 변수와 마찬가지로 구조체 배열 변수는 SELECT 문장에서의 출력 변수와 INSERT 문 장에서의 입력 변수로 사용할 수 있습니다.
구조체 배열 변수를 사용하는 방법은 일반적인 배열 변수와 동일하며, 배열 변수의 사용 방법에 대한 내용 은 구조체 배열 변수에도 동일하게 해당됩니다. 단순히 구조체 배열 변수만을 사용할 수도 있으며 커서와 함 께 사용할 수도 있습니다.
다음은 구조체 배열 변수를 입/출력 변수로 사용하는 예입니다.
Last updated

