배열 변수
배열 변수의 기본 개념과 선언 방법, 그리고 배열 변수를 tbESQL/C 문장에서 입/출력 변수로 사용하는 방법을 설명합니다.
개요
tbESQL/C 프로그램의 배열 변수는 C 프로그래밍 언어의 배열 변수의 개념과 동일합니다. 배열은 동일한 타입의 값을 여러개 저장할 수 있는 데이터 구조입니다.
tbESQL/C 프로그램에서는 SELECT 문장을 실행한 뒤 다수의 결과 로우를 저장하기 위해서 출력 변수로 배열 변수를 사용하거나, INSERT 문장을 사용할 때도 보통 여러 개의 로우를 삽입하게 되므로 입력 변수 로 배열 변수를 사용합니다.
배열 변수가 출력 변수로 사용될 때는 출력 배열 변수라고 부르며, 입력 변수로 사용될 때는 입력 배열 변수라고 합니다. 출력 배열 변수와 입력 배열 변수가 사용되는 문장은 다음과 같습니다.
출력 배열 변수
SELECT
입력 배열 변수
INSERT
UPDATE
DELETE
tbESQL/C 프로그램에서 tbESQL/C 문장과 C 프로그램의 변수 사이에 데이터를 주고 받을 때 배열 변수를 사용하면 다음과 같은 장점이 있습니다.
간결하고 구조적인 프로그래밍 배열 변수를 사용하면 각각의 로우를 처리할 때마다 별도의 SQL 문장을 사용하지 않고, 모든 로우를 하나의 SQL 문장으로 처리할 수 있습니다. 따라서 프로그램의 소스 코드를 보다 단순화할 수 있으며, 구조적인 프로그래밍이 가능합니다.
tbESQL/C 프로그램의 성능 향상 클라이언트와 서버 환경에서는 데이터를 주고받기 위하여 많은 시간이 필요합니다. 배열 변수를 사용해 여러 로우를 한꺼번에 처리하면 전송 시간이 크게 줄어듭니다.
배열 변수 선언
tbESQL/C 문장에서 사용될 배열 변수를 선언할 때에는 다음의 내용에 유의해야 합니다.
반드시 DECLARE 영역 안에 선언해야 합니다.
VARCHAR 또는 CHAR 타입 등의 문자열 타입 변수는 항상 2차원 배열이어야 합니다.
int 타입 등의 문자열이 아닌 변수는 항상 1차원 배열이어야 합니다.
포인터 변수를 배열 변수 형태로 선언하면, tbESQL/C 문장에서 사용할 수 없습니다.
다음은 배열 변수를 선언하는 예입니다.
다음은 배열 변수를 잘못 선언한 예입니다.
① VARCHAR 타입 변수는 2차원으로 선언되어야 하는데 3차원으로 잘못 선언된 예입니다.
② int 타입 등의 문자열이 아닌 변수는 1차원으로 선언되어야 하는데 2차원으로 잘못 선언된 예입니다.
③ 포인터 변수를 배열 변수로 선언해서 tbESQL/C 문장에 사용하려고 했기 때문에 잘못 선언된 예입니다.
입/출력 배열 변수
본 절에서는 tbESQL/C 문장에서 배열 변수가 입/출력 변수로 사용될 경우 각 tbESQL/C 문장에 따른 배열 변수의 사용 방법에 대해 설명합니다.
SELECT
SELECT 문장을 실행하여 반환되는 결과 로우의 개수가 하나 이상이라면 반드시 커서 또는 배열 변수를 사용해야 합니다. 결과 로우의 개수를 미리 예측할 수 있다면 배열 변수의 크기를 충분히 선언하여 사용할 수 있습니다. 만약 결과 로우의 개수가 예측하기 힘들거나 매우 크다면, 배열 변수와 커서를 함께 사용할 수도 있습니다.
배열 변수
SELECT 문장의 실행 결과로 반환된 로우의 개수가 예측 가능하고 크기가 크지 않다면 배열 변수를 이용하여 모든 결과 로우를 한 번에 받을 수 있습니다.
예를 들어 SELECT 문장의 결과로 반환되는 로우의 개수가 50개를 넘지 않는 경우에 다음과 같이 소스 코드를 작성할 수 있습니다.
[예 1] SELECT 문장에서의 배열 변수의 사용
결과 로우의 각 컬럼 값은 각 배열 변수에 저장되며, 저장될 때 같은 순서의 변수에 저장됩니다. 예를 들어 세 번째 로우의 컬럼 값은 각각 배열 변수의 세 번째 위치인 ename[2], salary[2], addr[2]에 저장됩니다.
SELECT 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
INTO 절에 포함되는 출력 변수는 배열 변수와 일반 변수가 동시에 함께 올 수 없습니다.따라서 INTO 절에 포함된 모든 출력 변수는 배열 변수이거나 또는 일반 변수이어야 합니다.
SELECT 문장의 실행 결과로 반환된 로우의 전부가 아닌 일부만을 얻고 싶을 때에도 배열 변수를 이용할 수 있습니다. 위의 [예 4.1]에서 SELECT 문장의 실행 결과로 반환된 로우가 50개가 넘는 경우에 50개 까지의 결과 로우만을 배열 변수에 저장합니다. 만약 결과로 반환된 로우를 30개 까지만 저장하고 싶다면, 위의 [예 4.1]의 배열 변수를 다음과 같이 선언하면 됩니다.
SELECT 문장의 실행 결과로 배열 변수에 저장된 로우의 실제 개수는 SQLCA의 변수인 sqlca를 통해 알 수 있습니다. 변수 sqlca는 tbESQL/C 프로그램 내에 포함된 변수로 주로 에러 및 경고 처리에 사용됩니다. sqlca의 사용에 대해서는 “SQLCA 구조체 변수”를 참고합니다. 정확하게는 sqlca.sqlerrd[2]에 실제로 변수에 저장된 로우의 개수가 저장됩니다. 다음은 SELECT 문의 실행 후에 올 수 있는 소스 코드에 sqlca.sqlerrd[2]를 사용한 예입니다.
[예 2] sqlca.sqlerrd[2]의 활용
맨 마지막 라인을 보면 반환된 로우의 개수를 출력하는 데 sqlca.sqlerrd[2]를 사용하였습니다.
배열 변수의 크기가 일정하지 않은 경우에는 가장 작은 배열 변수의 크기를 전체 배열 변수의 크기로 설정합니다. 예를 들어 다음의 소스 코드와 같이 배열 변수가 선언된 경우에 배열 변수 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의 변수인 sqlca를 사용해 루프를 빠져 나옵니다. 커서와 함께 배열 변수가 사용될 때에 sqlca.sqlerrd[2]에는 FETCH 문장을 수행할 때마다 현재까지 처리된 결과 로우의 누적 개수가 저장됩니다. 그러므로 이 누적 개수가 더 이상 증가하지 않을 때 루프를 중단하면 됩니다.
다음은 루프를 중단하는 소스 코드의 예입니다.
[예 3] sqlca.sqlerrd[2]를 활용한 루프의 중단
위의 예에서는 두 개의 새로운 변수 before_count와 current_count를 사용하여 두 변수의 값이 일치하면 while 루프를 중단합니다. 출력 배열 변수에 저장된 실제 결과 로우의 개수는 변수 count에 저장됩니다.
다수의 커서
SELECT 문장에는 배열 변수와 함께 다수의 커서를 사용할 수도 있습니다. 몇 개의 커서를 사용하더라도 하나의 커서를 사용할 때와 동일하게 처리됩니다.동시에 여러개의 커서를 사용할 때 SQLCA의 변수 sqlca가 각 커서마다 별도로 선언되지는 않습니다. 따라서 변수 sqlca에 저장된 데이터는 직전에 실행된 질의 또는 기타 SQL 문장의 결과에 대한 데이터입니다.
다음은 각 커서에 FETCH를 수행할 때마다 변수 sqlca에 저장되는 데이터의 예입니다.
위의 예에서 배열 변수 ename과 salary의 크기는 각각 20과 30이며, cursor1과 cursor2에 연관된 SELECT 문장의 결과 로우의 개수가 충분히 크다고 가정합니다.
스크롤 가능 커서
SELECT 문장에는 배열 변수와 함께 스크롤 가능 커서를 사용할 수도 있습니다. 스크롤 가능 커서는 일반 커서의 경우와 거의 동일하게 사용할 수 있으나, sqlca.sqlerrd[2]에 저장되는 값의 의미가 달라집니다.
일반 커서와 스크롤 가능 커서의 sqlca.sqlerrd[2] 값의 차이는 다음과 같습니다.
일반 커서의 sqlca.sqlerrd[2]
일반 커서의 경우에는 액세스된 결과 로우의 누적 개수를 저장하고 있음
스크롤 가능 커서의 sqlca.sqlerrd[2]
현재까지 액세스된 가장 마지막 결과 로우의 절대 위치를 저장하고 있음
참고
일반 커서의 sqlca.sqlerrd[2]와 관련된 예제는 [예 4.2]을 참고합니다. sqlca에 대한 자세한 내용은 “SQLCA 구조체 변수”를 참고합니다.
스크롤 가능 커서를 사용할 때 sqlca.sqlerrd[2]에 저장되는 값은 다음과 같이 결정됩니다.
FETCH 문장을 수행할 때마다 옵션에 의하여 정해진 결과 로우의 위치로부터 배열 변수의 크기만큼 액세스하게 되므로, sqlca.sqlerrd[2]에 저장되는 값은(액세스하고자 하는 결과 로우의 절대 위치 + 배열 변수 의 크기 - 1) 값 중에서 현재까지 가장 큰 값이 됩니다. 만약 액세스를 하려는 위치에서부터 남아 있는 결과 로우의 개수가 배열 변수의 크기보다 작다면 sqlca.sqlerrd[2]에 저장되는 값은 전체 결과 로우의 개수가 됩니다. 결과 로우의 절대 위치 값과 sqlca.sqlerrd[2] 값은 항상 1 이상입니다.
다음의 소스 코드는 배열 변수와 함께 스크롤 가능 커서를 사용하는 예입니다.
위의 예에서 배열 변수 ename의 크기는 20이며, 커서에 연관된 SELECT 문장의 결과로 반환된 로우의 전체 개수는 90이라고 가정합니다.
지시자 배열 변수
SELECT 문장에는 출력 배열 변수와 함께 지시자 배열 변수를 사용할 수 있습니다.
지시자 배열 변수는 출력 배열 변수와 같은 크기를 가져야 하며, 배열 변수로 선언합니다는 것 외에는 일반적인 지시자 변수와 동일하게 사용할 수 있습니다. 반환되는 컬럼 값이 NULL이거나 값의 일부가 잘릴 가능성이 있다면 지시자 배열 변수의 사용을 고려해야 합니다. 지시자 배열 변수도 다른 변수와 마찬가지로 DECLARE 영역 내에 선언합니다.
다음은 지시자 배열 변수를 사용한 예입니다.
참고
입력 배열 변수와 함께 지시자 배열 변수를 사용할 수도 있습니다. 입력 지시자 변수는 INSERT, UPDATE, DELETE 문장에서 사용할 수 있습니다.
사용 예제
다음은 [예 14]에서 제시한 예제를 배열 변수를 이용하도록 수정한 예입니다.
① [예 3.14]과 비교했을 때 변수를 배열 변수로 선언합니다.
② FETCH를 수행할 때 루프를 중단합니다.
③ 배열 변수에 저장된 컬럼의 값을 printf 문을 통해 출력합니다.
INSERT
INSERT 문장에서 배열 변수를 사용하는 방법은 일반적인 입력 변수를 사용하는 방법과 동일합니다. 입력 배열 변수가 사용되는 각 문장은 문장이 실행되기 직전에 동적으로 배열 변수에 저장된 값을 읽어 들입니다. 따라서 각 문장이 실행되기 전에 반드시 배열 변수에 적절한 값을 넣어 주는 코드가 있어야 합니다.
INSERT 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
INSERT 문장에서 사용되는 입력 변수는 배열 변수와 일반 변수가 함께 올 수 없습니다. 따라서 모든 입력 변수가 배열 변수이거나 일반 변수로만 구성되어야 합니다.
SELECT 문장에서와 마찬가지로 포인터 배열 변수를 입력 변수로 사용할 수 없습니다.
SELECT 문장과 유사하게 SQLCA의 변수 sqlca.sqlerrd[2]에는 삽입된 로우의 개수가 저장되어 있습니다. sqlca.sqlerrd[2]에는 항상 하나의 INSERT 문장에 의해 삽입된 로우의 개수만 저장됩니다.
FOR 절을 사용해 입력 배열 변수의 크기보다 적은 개수의 로우를 삽입하도록 할 수도 있습니다. 예를 들면 크기가 50인 입력 배열 변수의 내용 중에서 30개의 로우 값만을 이용하는 경우입니다.
입력 배열 변수와 함께 지시자 배열 변수를 사용할 수도 있습니다. 삽입해야 할 컬럼 값 중 일부만 NULL 값인 경우에는 반드시 지시자 배열 변수를 사용해야 합니다.
다음은 배열 변수와 함께 INSERT 문장을 실행하는 예입니다.
[예 4] INSERT 문장의 배열 변수
위의 [예 4]에서의 INSERT 문장은 다음의 for 루프를 이용한 소스 코드와 같은 결과를 갖습니다. 하지만 배열 변수를 이용하는 편이 서버와의 통신 비용을 크게 줄일 수 있으므로 성능 면에서 훨씬 효율적입니다.
다음은 컬럼 SALARY에 대해 지시자 배열 변수를 사용한 예입니다.
UPDATE
UPDATE 문장에서 배열 변수를 사용하는 방법도 일반 변수를 사용하는 방법과 유사합니다.
UPDATE 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
UPDATE 문장에서는 SELECT 문장과는 다르게 WHERE 절에도 배열 변수를 사용할 수 있습니다. WHERE 절에 배열 변수를 사용하면 SET 절에도 배열 변수를 사용해야 합니다. 만약 WHERE 절에 일반 변수를 사용하였다면 SET 절에도 일반 변수를 사용해야 합니다.
INSERT 문장과 유사하게, SQLCA의 변수 sqlca.sqlerrd[2]에는 갱신된 로우의 개수가 저장됩니다. sqlca.sqlerrd[2]에는 항상 하나의 UPDATE 문장에 의해 갱신된 로우의 개수만 저장되며, 무결성 제약조건을 만족하기 위해 연속적으로 갱신되거나 삭제된 로우의 개수는 포함되지 않습니다.
UPDATE 문장에서 SET 절 내에 사용된 입력 변수에는 배열 변수와 일반 변수가 함께 올 수 없습니다. 또한 입력 변수로 포인터 배열 변수를 사용할 수 없습니다.
SELECT FOR UPDATE 문장 내에서 UPDATE ... CURRENT OF 절과 함께 배열 변수를 사용할 수 없습니다.
다음은 UPDATE 문장의 SET 절과 WHERE 절에 배열 변수를 사용한 예입니다.
[예 5] UPDATE 문장의 배열 변수
위의 [예 5]은 다음과 같은 for 루프를 이용한 연속된 UPDATE 문장과 동일한 결과를 갖습니다. 하지만 배열 변수를 이용하는 편이 성능 면에서 더욱 효율적입니다.
DELETE
DELETE 문장에서 배열 변수를 사용하는 방법도 일반 변수를 사용하는 방법과 유사합니다.
DELETE 문장에서 배열 변수를 사용할 때는 다음의 사항에 유의해야 합니다.
DELETE 문장에서도 UPDATE 문장과 같이 WHERE 절에 배열 변수를 사용할 수 있습니다.
INSERT, UPDATE 문장에서와 유사하게, sqlca.sqlerrd[2]에는 삭제된 로우의 개수가 저장됩니다.
sqlca.sqlerrd[2]에는 항상 하나의 DELETE 문장에 의하여 삭제된 로우의 개수만 저장되며, 무결성 제약 조건을 만족하기 위하여 연속적으로 갱신되거나 삭제된 로우의 개수는 포함되지 않습니다.
DELETE 문장의 WHERE 절에 사용될 입력 변수로 배열 변수와 일반 변수가 함께 올 수 없습니다.
입력 변수로 포인터 배열 변수를 사용할 수 없습니다.
DELETE 문장에 배열 변수를 사용할 때는 DELETE ... CURRENT OF 절을 사용할 수 없습니다.
다음은 DELETE 문장의 WHERE 절에 배열 변수를 사용한 예입니다.
[예 6] DELETE 문장의 배열 변수
위의 [예 4.6]는 다음의 for 루프와 동일한 결과를 갖습니다. 하지만 INSERT, UPDATE 문장과 마찬가지로 배열 변수를 이용하는 편이 성능 면에서 효율적입니다.
FOR 절
INSERT, DELETE, UPDATE 문장에서 입력 배열 변수를 사용할 때 배열 변수의 크기보다 적은 개수의 로우를 처리하려는 경우에 FOR 절을 사용합니다. FOR 절은 EXEC SQL 바로 다음에 오며, 처리하고자 하는 로우의 개수를 명시합니다.
FOR 절에 로우의 개수를 명시할 때 다음의 사항에 유의해야 합니다.
FOR 절에 로우의 개수를 명시할 때는 숫자를 명시할 수도 있으며, 변수를 명시할 수도 있습니다. 변수를 명시할 경우 해당 변수는 반드시 DECLARE 영역에 선언되어 있어야 합니다.
FOR 절에 로우의 개수를 명시할 때 연산식을 사용해서는 안 됩니다.
FOR 절의 로우 개수는 항상 입력 배열 변수의 크기보다 작아야 합니다.
tbESQL/C 프로그램에서는 지정된 로우의 개수를 저장할 배열 변수의 크기를 검토하지 않습니다. 만약 지정된 로우의 개수보다 배열 변수의 크기가 작다면, 내부적으로 유효하지 않은 메모리에 접근하게 되어 메모리 에러가 발생하고, 이때 tbESQL/C 프로그램이 어떠한 동작을 할지 보장할 수 없습니다.
다음의 소스 코드는 FOR 절을 이용하는 예입니다.
① 로우의 개수를 숫자로 설정하여 FOR 절을 이용할 수 있습니다.
② 변수를 이용하여 로우의 개수를 설정하여 FOR 절을 이용할 수 있습니다. 단, 변수 row_count는 DECLARE영역에 선언되어 있어야 합니다.
다음은 FOR 절에서 로우의 개수를 명시할 때 임의의 연산식을 사용한 경우로 잘못된 예입니다.
구조체 배열 변수
tbESQL/C 문장 내에서 여러 컬럼을 동시에 처리할 때 각 컬럼별 입/출력 변수 각각을 나열할 수도 있지만, 각 컬럼에 대한 변수를 모아 하나의 구조체로 정의하여 구조체 타입의 변수를 이용할 수도 있습니다.
또한 더 나아가 각 컬럼의 여러 로우를 한꺼번에 처리하고자 할 때 구조체로 정의한 타입을 배열로 선언하여 구조체 배열 변수를 이용할 수 있습니다.
구조체 배열 변수의 선언
구조체 배열 변수를 선언할 때는 다음의 사항에 유의해야 합니다.
반드시 구조체 태그(tag)를 삽입해야 합니다.
구조체 배열 변수는 반드시 DECLARE 영역에 선언되어야 합니다.
tbESQL/C 문장에서 사용되는 구조체 타입의 변수는 중첩되어 정의될 수 없습니다. (일반적인 구조체 변수일 때나 구조체 배열 변수일 때나 동일하다)
다음은 구조체 태그를 삽입한 예입니다.
[예 7] 구조체 태그의 삽입
위의 예에서는 struct 예약어 다음에 tag_emp라는 태그를 삽입했습니다. 만약 구조체 태그를 넣지 않으면 프리 컴파일 과정에서 에러가 발생합니다.
다음은 구조체를 잘못 선언한 예입니다.
위의 예에서는 구조체 emp 내부에 구조체 sub_info를 중첩하여 정의하였습니다. 구조체 타입의 변수는 중첩 되어 정의될 수 없습니다.
지시자 구조체 배열 변수를 선언할 수도 있습니다. 지시자 구조체 배열 변수를 선언할 때도 구조체 배열 변수를 선언할 때의 유의점을 따라야 합니다. 그 밖에는 지시자 구조체 타입의 변수를 선언하는 방법과 유사합니다. 추가적으로 지시자 구조체 배열 변수를 선언할 때는 다음의 사항에 유의해야 합니다.
지시자 구조체 타입의 변수 내의 멤버 변수의 개수는 입/출력 구조체 타입의 변수 내의 멤버 변수의 개수와 같아야 하며, 각 멤버 변수는 서로 순서에 맞게 대응되도록 정의해야 합니다.
지시자 변수는 항상 short 타입을 가지며, 지시자 구조체 배열 변수도 반드시 DECLARE 영역 내에 선언되어야 합니다.
다음은 위의 [예 7]에서 선언한 emp 구조체 배열 변수를 지시자 배열 변수 형태로 선언한 예입니다.
사용 방법
단순 구조체 타입의 변수와 마찬가지로 구조체 배열 변수는 SELECT 문장에서의 출력 변수와 INSERT 문장에서의 입력 변수로 사용할 수 있습니다. 두 가지 경우 모두 지시자 구조체 배열 변수를 함께 사용할 수 있습니다. 입/출력 값 중에 NULL이 포함되거나 출력 값 중에 일부가 잘릴 가능성이 있다면 반드시 지시자 구조체 배열 변수를 사용해야 합니다.
구조체 배열 변수를 사용하는 방법은 일반적인 배열 변수와 동일하며, 배열 변수의 사용 방법에 대한 내용은 구조체 배열 변수에도 동일하게 해당됩니다. 단순히 구조체 배열 변수만을 사용할 수도 있으며 커서와 함께 사용할 수도 있습니다.
다음은 구조체 배열 변수를 입/출력 변수로 사용하는 예입니다.
위에서는 INSERT 문장에 입력 배열 변수 emp와 지시자 구조체 배열 변수 emp_ind를 함께 사용하였습니다.
구조체 배열 변수 대신에 구조체 배열 변수에 대한 포인터 변수를 사용할 수도 있습니다. 단, 포인터의 배열 변수는 사용할 수 없다. 이러한 포인터 변수는 구조체 배열 변수를 함수 파라미터로 넘길 때에 유용합니다.
다음은 포인터 변수를 사용하는 예입니다.
Last updated

