From Zero to SAP

[ABAP 실습] Open SQL JOIN & CRUD 연습 문제 풀이 본문

ABAP/실습

[ABAP 실습] Open SQL JOIN & CRUD 연습 문제 풀이

권쌥 2026. 4. 9. 17:04

LEVEL 1 — 문법 익히기

문법이 손에 익는 게 목적이다.


문제 1. ZTEMP 테이블에서 부서코드가 D001인 직원의 emp_id와 emp_name을 조회하세요.


문제 2. ZTEMP 테이블에서 salary가 300만 이상 350만 이하인 직원을 조회하세요.

ENDSELECT 쓰고 안쓰고 기준?
INTO TABLE
→ 결과를 한 번에 다 가져와서 인터널 테이블에 담는 거라 ENDSELECT 불필요

INTO 구조체 → 한 건씩 가져오면서 루프 처리하는 방식이라 어디서 끝낼지 알려줘야 함


문제 3. 신규 직원 데이터를 INSERT 하세요.

  • emp_id: '1006', emp_name: '홍길동', dept_cd: 'D001', salary: 2500000, join_date: '20240401'

일부러 방식을 2가지로 구분해서 SQL을 작성했다.

방법 1은 ztempData 변수가 남아있어서 INSERT 후에도 다른 곳에서 쓸 수 있고,

방법 2는 INSERT 하고 나면 데이터가 사라진다.

그래서 삽입 후 그 데이터를 또 쓸 일이 있으면 방법 1, 한 번 쓰고 끝이면 방법 2가 깔끔하다.


문제 4. emp_id가 '1006'인 직원의 salary를 2800000으로 UPDATE 하세요. SET + WHERE 방식으로 작성하세요.

 

MODIFY를 사용할 수도 있다. (존재하면 UPDATE, 없으면 INSERT)

MODIFY는 수정할 원본 데이터를 먼저 SELECT로 가져온 다음, 원하는 필드 값만 바꾼다.

그리고 수정된 구조체를 MODIFY로 전달하면, 키 값 기준으로 기존 행 전체를 덮어씌운다.

키 값에 해당하는 행이 없으면 INSERT, 있으면 UPDATE가 실행된다.


문제 5. emp_id가 '1006'인 직원을 DELETE 하세요.

DELETE 구문을 사용할 때에는 반드시 WHERE절을 신경쓰도록 하자. 안그러면 모든 데이터가 삭제된다 ..

 


LEVEL 2 — JOIN 활용

단순 조회가 아니라 두 테이블을 연결해서 원하는 결과를 만드는 게 목적임.

ZTFAMILY_STUDY 테이블 (emp_id, fname, relate 필드)에 아래 데이터가 있다고 가정하자.

ZTFAMILY_STUDY 테이블

@AbapCatalog.foreignKey.keyType : #KEY

-> 이 필드가 테이블의 키 컬럼임을 명시 " #KEY / #KEY_NO_DUPLICATE 중 선택, 보통 #KEY @AbapCatalog.foreignKey.screenCheck : false

→ 화면에서 입력할 때 외래키 존재 여부 체크할지 -> true면 입력 시 참조 테이블에 없는 값 막음.

-> 실제 운영 또는 데이터 정합성 중요할 때는 true로 하는 것이 맞다.

INSERT INTO ztfamily_study VALUES @( VALUE #( client = '100' emp_id = '1001' fname = '김아버지' relate = '부' ) ).
INSERT INTO ztfamily_study VALUES @( VALUE #( client = '100' emp_id = '1001' fname = '김어머니' relate = '모' ) ).
INSERT INTO ztfamily_study VALUES @( VALUE #( client = '100' emp_id = '1002' fname = '이배우자' relate = '배우자' ) ).
COMMIT WORK.

문제 6. ZTEMP와 ZTFAMILY_STUDY를 INNER JOIN해서 직원 이름과 가족 이름을 함께 조회하세요.

[1차 코드]

처음 작성했을 때는 몇 가지 문법 오류가 발생했다.

문제 1 — - 대신 ~ 사용

ABAP에서 테이블 별칭과 필드명은 .이나 -가 아니라 ~로 연결한다

문제 2 — AS 뒤에 한글 문자열 사용 불가

별칭은 영문자, 숫자, 언더스코어만 가능하다. 또한, 별칭은 그냥 이름이라서 따옴표 없이 바로 써야한다.

문제 3 — INTO 절 없음 (결과를 담을 곳을 지정해야한다)

 

[최종 코드]

직원 테이블(ZTEMP)의 emp_id와 직원가족 테이블(ZTFAMILY) 테이블에 있는 emp_id가 일치하는 필드를 JOIN했다.

가족 정보와 직원 정보를 합쳐서 의미있는 데이터를 만들어냈다.


문제 7. 문제 6을 LEFT OUTER JOIN으로 바꿔서 가족이 없는 직원도 포함해서 조회하세요. 가족이 없는 경우 fname을 '가족 없음'으로 표시하세요. (힌트: COALESCE)

 

COALESCE를 사용해서 데이터가 없는 경우 '가족 없음' 데이터를 넣도록 처리했다.

직원 테이블 기준으로 LEFT (OUTER) JOIN을 했기 때문에 교집합 뿐만 아니라 직원 테이블의 모든 필드가 결과 데이터에 반영된다.

 


문제 8. 부서별 평균 급여를 구하세요. 결과는 평균 급여가 높은 순으로 정렬하세요. (힌트: GROUP BY, AVG, ORDER BY)

[1차 코드]

 

문제 1 — INTO TABLE 위치

ABAP에서 INTO TABLE은 반드시 ORDER BY 앞에 와야 한다.

 

문제 2 — DATA 선언 위치

DATA 선언은 해당 메서드나 프로그램의 최상단에 몰아서 쓰는 게 원칙이다.

 

[2차 코드]

 

여전히 오류가 남아있다.

"AVG_SALARY" nested in "ZS_RESULT" at 40(8) is not compatible with "AVG_SALARY" nested in line type of "ZT_RESULT" at 40(8) (see long text).

오류는 타입 호환성 문제로 해석되었다.

zs_result 구조체 필드인 avg_salary는 ztemp 테이블의 salary 타입을 참조하고 있다. 즉, 정수를 참조하고 있다.

그러나, AVG() 함수의 반환 타입은 항상 DECFLOAT16 또는 DEC 계열이다.  따라서 수정해주어야 한다.

(참고)ABAP 숫자 타입 정리

Dictionary 타입 (SE11 기준)

DEC p 고정소수점, 최대 31자리 일반 금액, 수량
CURR p 통화금액, DEC와 동일하나 통화키 참조 salary, price
QUAN p 수량, DEC와 동일하나 단위 참조 재고수량
FLTP f 부동소수점 8바이트 과학계산
DECFLOAT16 decfloat16 10진 부동소수점 16자리  
DECFLOAT34 decfloat34 10진 부동소수점 34자리  
INT1 b 정수 1바이트 (0~255)  
INT2 s 정수 2바이트  
INT4 i 정수 4바이트 일반 카운터
INT8 int8 정수 8바이트  

[최종 코드]


LEVEL 3 — 실무 활용 능력 키우기

어떤 테이블을 기준으로 잡을지, 조건을 어떻게 조합할지 먼저 생각하고 코드를 짜는 연습이 목적이다.

 

문제 9. 가족 정보가 등록된 직원 중에서 salary가 가장 높은 직원의 이름과 급여를 조회하세요.


우선, 가족 정보가 등록된 직원 중이기 때문에 내부 조인을 고려했다.

이후 salary 순으로 내림차순 정렬하고 UP TO 1 ROWS를 통해 상위 1행(직원 이름, 급여)만 조회하도록 설계했다.


문제 10. 부서별로 가장 오래 근무한 직원(join_date가 가장 이른 직원)의 이름, 부서코드, 입사일을 조회하세요.

우선, 2번의 조회로 나눠서 해결을 하고자 했다.

실무에서도 대용량 데이터를 다룰 때는 한 번의 쿼리에서 데이터를 조회하기 보다는 나눠서 처리하는 것이 성능이 좋다.

(물론 지금은 데이터가 많지는 않지만 연습용으로..)

 

1차 SELECT - 부서별 MIN(join_date) 조회 → lt_min에 저장

부서별로 가장 빠른 입사일 데이터를 조회했다.

 

2차 SELECT - lt_min을 FOR ALL ENTRIES IN으로 사용해서 dept_cd + join_date 두 조건으로 원본 테이블에서 이름까지 조회 

 

가독성을 위해 SORT 구문을 사용하여 부서 번호 순으로 정렬해줬다.


 

문제 11. ZTEMP 테이블의 모든 직원에 대해 ZTFAMILY_STUDY에 가족 정보가 있으면 기존 데이터를 유지하고, 없으면 emp_id만 넣고 fname은 '미등록'으로 INSERT 하는 코드를 작성하세요. 

 

문제를 보자마자 MODIFY를 사용하면 되겠다는 생각이 들었다.

가족 정보가 있으면 UPDATE, 없으면 INSERT => MODIFY

 

MODIFY 같은 경우 데이터를 조회해와서 구조체 필드를 수정하고 덮어씌우는 식이다.

찾아보니까 꼭 LOOP AT으로 하나하나 안돌고 아래와 같이 작성해도 된다. (코드가 훨씬 간결해진다)

IF lt_missing IS NOT INITIAL.
    INSERT ztfamily_study FROM TABLE @( VALUE #(
        FOR ls IN lt_missing (
            emp_id = ls-emp_id
            fname  = '미등록'
        )
    ) ).
ENDIF.

문제 풀이를 진행하면서 사소한 문법 실수들이 여전히 많다는 것을 느꼈다.

JOIN, CRUD뿐 아니라 기본 문법들도 이번 기회에 더 확실하게 정리할 수 있었다.

또한 SAP 개발에서는 결과가 나온다고 끝이 아니라, 대용량 데이터를 다루는 실무 환경을 염두에 두고 조회 성능까지 고민하는 습관이 필요하다는 것도 깨달았다.