백엔드DB / SQL
3

MariaDB에서 INSERT 중 같은 테이블을 SELECT 하면 안 되는 이유

실무에서 만난 에러와 해결 과정을 기록합니다.

MariaDB에서 INSERT 중 같은 테이블을 SELECT 하면 안 되는 이유

문제의 시작

경비 등록 기능을 개발하던 중 데이터를 저장할 때 일련번호(SEQ)를 자동으로 채번해야 했다.
가장 간단한 방법은 현재 최대값에 +1 하는 것이었다.

INSERT INTO TB_EXPENSE (
    SPDNG_SEQ,
    ...
) VALUES (
    (SELECT IFNULL(MAX(SPDNG_SEQ), 0) + 1 FROM TB_EXPENSE),  -- 같은 테이블 조회
    ...
)

논리적으로는 문제없어 보였다.
"지금 넣으려는 테이블에서 MAX 값 가져와서 +1 하면 되지 않나?"


에러 발생

Table 'TB_EXPENSE' is specified twice, 
both as a target for 'INSERT' and as a separate source for data

MariaDB가 이렇게 말하고 있다.

"너 지금 INSERT 하려는 테이블을 동시에 SELECT 하고 있잖아. 그건 안 돼."


왜 안 되는 걸까?

MariaDB(MySQL 포함)는 DML 대상 테이블을 동시에 읽을 수 없다는 규칙이 있다.

DB동일 테이블 INSERT + SELECT
MariaDB / MySQL❌ 불가
PostgreSQL✅ 가능
Oracle✅ 가능

이유는 데이터 일관성 때문이다.
INSERT가 진행되는 도중에 같은 테이블을 읽으면, 아직 커밋되지 않은 데이터가 섞여 예측 불가능한 결과가 나올 수 있다.
MariaDB는 이 상황을 아예 차단해버린다.


해결 방법: 서브쿼리 래핑

MariaDB가 거부하는 이유는 INSERT 대상 테이블과 SELECT 대상 테이블이 동일하다고 인식하기 때문이다.
서브쿼리로 한 번 감싸면 MariaDB는 이걸 별도의 임시 결과(파생 테이블) 로 인식한다.

-- ❌ 에러 발생
INSERT INTO TB_EXPENSE (SPDNG_SEQ, ...)
VALUES (
    (SELECT IFNULL(MAX(SPDNG_SEQ), 0) + 1 FROM TB_EXPENSE),
    ...
)

-- ✅ 서브쿼리 래핑으로 해결
INSERT INTO TB_EXPENSE (SPDNG_SEQ, ...)
VALUES (
    (SELECT t.next_seq 
       FROM (SELECT IFNULL(MAX(SPDNG_SEQ), 0) + 1 AS next_seq 
               FROM TB_EXPENSE) AS t),
    ...
)

동작 원리:

1. 가장 안쪽 SELECT 먼저 실행
   → SELECT IFNULL(MAX(SPDNG_SEQ), 0) + 1 FROM TB_EXPENSE
   → 결과: 임시 파생 테이블 t { next_seq: 5 }

2. 외부 SELECT는 파생 테이블 t를 조회
   → SELECT t.next_seq FROM t
   → 결과: 5

3. INSERT 실행
   → TB_EXPENSE에 SPDNG_SEQ = 5 로 삽입

MariaDB 입장에서 FROM TB_EXPENSE는 이미 파생 테이블로 변환됐기 때문에
INSERT 대상인 TB_EXPENSE다른 것으로 인식한다.


정리

항목내용
에러 코드1093 HY000
에러 메시지Table is specified twice, both as a target for INSERT and as a separate source for data
원인MariaDB는 INSERT 대상 테이블을 동시에 SELECT 불가
해결서브쿼리로 한 번 감싸서 파생 테이블로 만들기

느낀 점

처음엔 "논리적으로 맞는데 왜 에러지?" 싶었다.
에러 메시지를 자세히 읽어보니 MariaDB가 친절하게 이유를 설명해주고 있었다.

에러 메시지를 대충 보지 말고 천천히 읽는 것만으로도 해결의 실마리가 보인다.


잘못된 내용이 있다면 댓글로 알려주세요!

댓글

(0)
MariaDB에서 INSERT 중 같은 테이블을 SELECT 하면 안 되는 이유 | 강민석의 개발블로그