출하 한 건의 상태만 'S'로 바꾸려고 작업 영역에 키와 STATUS만 넣은 뒤 UPDATE zship_status FROM @ls_ship.을 실행하면, sy-subrc는 0인데 그 행의 운송사, 예정일, 변경자 칼럼이 빈 값이 됩니다. 이 글을 읽고 나면 UPDATE … FROM 작업 영역이 행의 어디까지 바꾸는지 설명할 수 있고, 칼럼 몇 개만 바꾸려던 자리를 SET, INDICATORS, 먼저 읽고 고쳐 쓰기 가운데 하나로 고칠 수 있습니다.
예시는 가상 Z 테이블 ZSHIP_STATUS(키 MANDT, SHIP_ID, 일반 칼럼 STATUS, CARRIER, PLAN_DATE, CHANGED_BY)와 가상 프로그램 ZDEMO_SHIP_STATUS입니다. 출하 0000004711 행은 처음에 STATUS P, CARRIER C001, PLAN_DATE 20261120, CHANGED_BY USER_A입니다. 코드는 실제 시스템에서 실행하지 않았습니다. 동작은 ABAP 키워드 문서 7.58판의 UPDATE source 설명(영어)과 관련 페이지에 적힌 대로 옮겼습니다.
FROM 작업 영역은 행 전체를 바꾼다
UPDATE로 데이터베이스 테이블을 바꾸는 길은 둘입니다. SET 뒤에 바꿀 칼럼을 적거나, FROM 뒤에 작업 영역을 주어 행 전체를 덮어쓰는 것입니다. FROM @ls_ship은 작업 영역 앞부분의 기본 키 값으로 같은 행을 찾고, 찾은 행에 작업 영역 내용을 그대로 씁니다. 변환 없이 왼쪽부터 차례로 들어가며, '값을 넣은 칼럼만'이라는 구분은 없습니다.
위 예에서 ls_ship은 테이블을 참조해 선언했으므로 구조는 맞습니다. 하지만 값을 넣은 것은 ship_id와 status뿐입니다. 나머지 세 칼럼에는 형식의 초기값, 곧 문자 칼럼은 공백, 날짜 칼럼은 00000000이 들어 있고, 이 값도 행에 그대로 쓰입니다. 작업 영역의 클라이언트 칼럼은 무시되고 현재 클라이언트의 행이 바뀝니다. 다른 클라이언트를 대상으로 하려면 USING CLIENT 같은 추가 구문을 따로 씁니다.
sy-subrc 0은 '행을 찾아 바꿨다'는 뜻일 뿐이다
이 실수가 오래 남는 이유는 결과가 정상으로 보이기 때문입니다. 작업 영역으로 UPDATE하면 지정한 행을 바꿨을 때 sy-subrc가 0이고, 바꾼 행 수 sy-dbcnt는 1입니다. 4가 되는 것은 행을 하나도 바꾸지 못했을 때입니다. 키가 같은 행이 없거나, 바꾸면 기본 키나 고유 보조 인덱스에 중복이 생기는 경우입니다. 행이 없어도 UPDATE는 새 행을 넣지 않습니다.
그래서 IF sy-subrc <> 0. 검사는 '그 출하가 있었는가'만 확인합니다. 어느 칼럼이 무엇으로 바뀌었는지는 어떤 시스템 필드도 알려 주지 않습니다. 테스트에서 STATUS가 S로 바뀐 것만 보고 넘어가면, 운송사와 예정일이 빈 행이 운영에 그대로 남습니다.
SAP 노트
같은 행에 세 가지 UPDATE
가상 테이블 ZSHIP_STATUS, 키 SHIP_ID 0000004711의 STATUS만 'S'로 바꾸려 할 때
UPDATE 전의 행
- STATUS P
- CARRIER C001
- PLAN_DATE 20261120
- CHANGED_BY USER_A
UPDATE … FROM @ls_ship
sy-subrc 0 · sy-dbcnt 1- STATUS S
- CARRIER 빈칸(초기값)
- PLAN_DATE 00000000(초기값)
- CHANGED_BY 빈칸(초기값)
UPDATE … SET status = 'S'
WHERE ship_id = @lv_ship_id- STATUS S
- CARRIER C001
- PLAN_DATE 20261120
- CHANGED_BY USER_A
FROM … INDICATORS (7.55 이상)
SET STRUCTURE col_ind- col_ind-status에만 'X'
- STATUS만 S로 바뀜
- 나머지 세 칼럼은 그대로
- 키 칼럼에는 표시가 효과 없음
세 문장 모두 sy-subrc 0으로 끝납니다. 행이 어떻게 바뀌었는지는 sy-subrc가 알려 주지 않습니다. 테이블, 키, 값은 가상입니다.
칼럼 몇 개만 바꿀 때는 SET
바꾸려는 것이 STATUS 하나라면 처음부터 UPDATE zship_status SET status = 'S' WHERE ship_id = @lv_ship_id.로 씁니다. SET 뒤에는 바꿀 칼럼을 쉼표로 이어 적고, col = col + f처럼 지금 값에 더하는 형태도 쓸 수 있습니다. 한 칼럼은 한 번만 적을 수 있습니다. 적지 않은 칼럼은 이 문장이 건드리지 않습니다.
SET에는 다른 위험이 하나 있습니다. WHERE를 빠뜨리면 대상 테이블의 모든 행, 클라이언트 종속 테이블이라면 현재 클라이언트의 모든 행이 바뀝니다. SET을 쓴 문장은 한 행 이상 바꾸면 sy-subrc가 0이므로, 키 하나를 바꾸려던 문장이라면 실행 뒤 sy-dbcnt가 1인지 확인하는 편이 안전합니다.
구조로 넘겨야 한다면 INDICATORS (7.55 이상)
여러 행을 내부 테이블로 한 번에 바꾸거나 구조 단위로 값을 주고받는 코드라면 SET으로 옮기기 어렵습니다. ABAP 7.55부터는 UPDATE … FROM 뒤에 표시 구조(set indicator)를 붙여 바꿀 칼럼을 고를 수 있습니다. 7.55 릴리스 노트에 TYPES의 INDICATORS 추가 구문과 UPDATE FROM 뒤의 표시 구조가 함께 새 항목으로 실려 있습니다.
먼저 TYPES ty_ship_ind TYPE zship_status WITH INDICATORS col_ind TYPE abap_bool.처럼, 테이블 구조 끝에 칼럼마다 한 글자짜리 표시를 가진 하위 구조 col_ind를 붙인 형식을 만듭니다. 그 형식의 작업 영역에 키와 새 STATUS를 넣고 col_ind-status에만 'X'를 넣은 뒤 UPDATE zship_status FROM @ls_ship_ind INDICATORS SET STRUCTURE col_ind.을 실행하면 STATUS만 바뀝니다. 표시가 'X'가 아닌 칼럼은 바뀌지 않고, NOT SET으로 쓰면 거꾸로 'X'인 칼럼만 빼고 바뀝니다. 키 칼럼도 표시 구조에 들어 있어야 하지만 키 칼럼의 표시는 아무 효과가 없습니다. 7.55보다 앞선 릴리스에서는 이 문법을 쓸 수 없으니 SET이나 아래의 먼저 읽기 방식을 씁니다.
먼저 읽고 고쳐 쓰기, 그리고 MODIFY
행 전체를 쓰는 것이 맞는 경우도 있습니다. 그럴 때는 SELECT SINGLE * FROM zship_status WHERE ship_id = @lv_ship_id INTO @ls_ship.으로 지금 행을 모두 읽고, 필요한 칼럼만 바꾼 뒤 FROM @ls_ship으로 씁니다. 나머지 칼럼은 읽은 값이 그대로 다시 쓰이므로 비지 않습니다. 다만 읽은 뒤 쓰기 전 사이에 다른 프로그램이 CARRIER를 바꿨다면, 그 변경은 읽어 둔 옛 값으로 덮입니다. 같은 행을 여러 곳에서 고칠 수 있다면 읽기 전에 SAP 잠금을 거는 것이 전제입니다.
MODIFY zship_status FROM @ls_ship.도 같은 규칙을 따릅니다. 키가 같은 행이 있으면 UPDATE 규칙대로 덮어쓰고, 없으면 INSERT 규칙대로 새 행을 넣습니다. 키와 STATUS만 채운 작업 영역으로 MODIFY를 실행하면, 행이 있을 때는 앞의 예처럼 칼럼이 비고, 없을 때는 나머지 칼럼이 초기값인 새 행이 생깁니다. 확인한 7.58판 문서의 MODIFY 작업 영역 설명에는 INDICATORS가 나오지 않습니다.
SAP 노트
무엇으로 바꿔 쓸까
바꾸려는 범위에 따라 고르는 네 문장, 가상 테이블 ZSHIP_STATUS 기준
칼럼 몇 개만 바꾼다
SET status = 'S'- UPDATE … SET col = … WHERE 키
- SET에 적은 칼럼만 바뀜
- WHERE가 없으면 클라이언트 전체 행
- 바뀐 행 수는 sy-dbcnt
구조로 넘기되 일부만 (7.55 이상)
INDICATORS SET STRUCTURE- TYPES … WITH INDICATORS col_ind
- 바꿀 칼럼의 표시에 'X'
- NOT SET이면 'X'만 빼고 바뀜
- 그 이전 릴리스에는 문법 없음
행 전체를 쓰는 게 맞다
UPDATE … FROM @ls_ship- 먼저 SELECT SINGLE *로 행 전체를 읽음
- 필요한 칼럼만 바꾼 뒤 FROM으로 씀
- 읽은 뒤 남이 바꾼 값도 덮어씀
- 읽기 전에 잠금이 필요
MODIFY … FROM도 같다
MODIFY zship_status FROM @ls_ship- 키가 같은 행이 있으면 UPDATE처럼 덮어씀
- 없으면 INSERT처럼 새 행을 넣음
- 작업 영역을 일부만 채웠다면
- 새 행의 나머지 칼럼은 초기값
확인한 판은 ABAP 키워드 문서 7.58입니다. INDICATORS는 7.55 릴리스 노트에 추가 항목으로 나옵니다. 테이블과 값은 가상입니다.
코드에서 먼저 찾아볼 곳
프로그램에서 UPDATE나 MODIFY 뒤에 FROM 작업 영역이 오는 줄을 찾고, 그 작업 영역이 어디서 채워졌는지 거슬러 올라가 봅니다. 새로 선언하거나 CLEAR한 뒤 몇 칼럼만 넣었다면 이 글의 경우입니다. 같은 행을 SELECT SINGLE *로 읽어 채웠다면 칼럼이 비지는 않으니, 잠금이 있는지를 함께 봅니다.
FROM 작업 영역을 볼 때마다 '이 작업 영역의 모든 칼럼이 지금 데이터베이스에 남아야 할 값인가'를 물어보세요. 아니라고 답하는 칼럼이 하나라도 있으면 그 문장은 SET이나 INDICATORS로 바꿀 자리입니다.
이 기록에 대화를 더해 주세요.
궁금한 점, 다른 접근, 직접 해 본 결과를 나눠 주세요.
로그인 상태 확인 중…
댓글을 불러오는 중…