백엔드›DB / SQL•
3분
•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가 친절하게 이유를 설명해주고 있었다.
에러 메시지를 대충 보지 말고 천천히 읽는 것만으로도 해결의 실마리가 보인다.
잘못된 내용이 있다면 댓글로 알려주세요!