RETURNING

RETURNING

RETURNING 절은 단독으로 쓰이는 명령문이 아니라, DELETE, INSERT, UPDATE 명령문의 일부로 사용돼요. 이 절을 통해 애플리케이션은 방금 삽입, 삭제, 또는 갱신된 행의 값을 얻을 수 있어요.

출처: 문서

본문

1. 개요

returning-clause:

RETURNING expr AS column-alias * ,

expr:

literal-value bind-parameter schema-name . table-name . column-name unary-operator expr expr binary-operator expr function-name ( function-arguments ) filter-clause over-clause ( expr ) , CAST ( expr AS type-name ) expr COLLATE collation-name expr NOT LIKE GLOB REGEXP MATCH expr expr ESCAPE expr expr ISNULL NOTNULL NOT NULL expr IS NOT DISTINCT FROM expr expr NOT BETWEEN expr AND expr expr NOT IN ( select-stmt ) expr , schema-name . table-function ( expr ) table-name , NOT EXISTS ( select-stmt ) CASE expr WHEN expr THEN expr ELSE expr END raise-function

filter-clause:

FILTER ( WHERE expr )

function-arguments:

DISTINCT expr , * ORDER BY ordering-term ,

ordering-term:

expr COLLATE collation-name DESC ASC NULLS FIRST NULLS LAST

literal-value:

CURRENT_TIMESTAMP numeric-literal string-literal blob-literal NULL TRUE FALSE CURRENT_TIME CURRENT_DATE

over-clause:

OVER window-name ( base-window-name PARTITION BY expr , ORDER BY ordering-term , frame-spec )

frame-spec:

GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING RANGE ROWS UNBOUNDED PRECEDING expr PRECEDING CURRENT ROW expr PRECEDING CURRENT ROW expr FOLLOWING expr PRECEDING CURRENT ROW expr FOLLOWING EXCLUDE CURRENT ROW EXCLUDE GROUP EXCLUDE TIES EXCLUDE NO OTHERS

ordering-term:

expr COLLATE collation-name DESC ASC NULLS FIRST NULLS LAST

raise-function:

RAISE ( ROLLBACK , expr ) IGNORE ABORT FAIL

select-stmt:

WITH RECURSIVE common-table-expression , SELECT DISTINCT result-column , ALL FROM table-or-subquery join-clause , WHERE expr GROUP BY expr HAVING expr , WINDOW window-name AS window-defn , VALUES ( expr ) , , compound-operator select-core ORDER BY LIMIT expr ordering-term , OFFSET expr , expr

common-table-expression:

table-name ( column-name ) AS NOT MATERIALIZED ( select-stmt ) ,

compound-operator:

UNION UNION INTERSECT EXCEPT ALL

join-clause:

table-or-subquery join-operator table-or-subquery join-constraint

join-constraint:

USING ( column-name ) , ON expr

join-operator:

NATURAL LEFT OUTER JOIN , RIGHT FULL INNER CROSS

ordering-term:

expr COLLATE collation-name DESC ASC NULLS FIRST NULLS LAST

result-column:

expr AS column-alias * table-name . *

table-or-subquery:

schema-name . table-name AS table-alias INDEXED BY index-name NOT INDEXED table-function-name ( expr ) , AS table-alias ( select-stmt ) ( table-or-subquery ) , join-clause

window-defn:

( base-window-name PARTITION BY expr , ORDER BY ordering-term , frame-spec )

frame-spec:

GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING RANGE ROWS UNBOUNDED PRECEDING expr PRECEDING CURRENT ROW expr PRECEDING CURRENT ROW expr FOLLOWING expr PRECEDING CURRENT ROW expr FOLLOWING EXCLUDE CURRENT ROW EXCLUDE GROUP EXCLUDE TIES EXCLUDE NO OTHERS

type-name:

name ( signed-number , signed-number ) ( signed-number )

signed-number:

+ numeric-literal -

RETURNING 절은 그 자체로 문(statement)이 아니라, 최상위 DELETE, INSERT, UPDATE 문의 끝부분에 선택적으로 위치할 수 있는 절이에요. RETURNING 절의 효과는 해당 문이 삭제·삽입·갱신되는 각 데이터베이스 행마다 결과 행 하나를 반환하도록 하는 거예요. RETURNING은 표준 SQL이 아니라 확장 기능이에요. SQLite의 RETURNING 구문은 PostgreSQL을 본떠 만든 거예요.

RETURNING 구문은 SQLite 버전 3.35.0(2021-03-12)부터 지원됐어요.

1.1. 일반적인 사용

RETURNING 절은 SQLite가 자동으로 채우는 열의 값을 애플리케이션에 제공하기 위해 설계됐어요. 예를 들어:

CREATE TABLE t0(
  a INTEGER PRIMARY KEY,
  b DATE DEFAULT CURRENT_TIMESTAMP,
  c INTEGER
);
INSERT INTO t0(c) VALUES(random()) RETURNING *;

위의 INSERT 문에서 SQLite는 세 열 모두의 값을 계산해요. RETURNING 절은 SQLite가 선택된 값을 애플리케이션에 다시 보고하도록 해요. 이 덕분에 애플리케이션은 정확히 어떤 값이 삽입됐는지 알아내기 위해 별도의 쿼리를 실행할 필요가 없어요.

2. 상세 내용

RETURNING 절 뒤에는 쉼표로 구분된 표현식 목록이 와요. 이 표현식들은 결과 집합의 열 값을 정의한다는 점에서 SELECT 문에서 SELECT 키워드 뒤에 오는 표현식들과 비슷해요. 각 표현식은 하나의 열 값을 정의해요. 각 표현식 뒤에는 결과 열의 이름을 정하는 AS 절이 선택적으로 올 수 있어요. 특별한 * 표현식은 삭제·삽입·갱신 대상 테이블의 숨겨지지 않은 모든 열 목록으로 확장돼요.

INSERT 및 UPDATE 문에서 수정 대상 테이블의 열을 참조하면 변경이 적용된 이후의 해당 열 값을 의미해요. DELETE 문에서 열을 참조하면 삭제가 발생하기 이전의 값을 의미해요.

RETURNING 절은 DELETE, INSERT 또는 UPDATE 문이 직접 수정한 행만 반환해요. RETURNING 절은 외래 키 제약 조건이나 트리거로 인한 추가적인 데이터베이스 변경 사항은 보고하지 않아요.

UPSERT의 RETURNING 절은 삽입된 행과 갱신된 행을 모두 보고해요.

2.1. 처리 순서

RETURNING 절이 포함된 DELETE, INSERT 또는 UPDATE 문을 실행하면 모든 데이터베이스 변경이 첫 번째 sqlite3_step() 호출 중에 일어나요. RETURNING 절 출력은 메모리에 쌓여요. 첫 번째 sqlite3_step() 호출은 RETURNING 출력의 행 하나를 반환하고, 이후의 sqlite3_step() 호출들이 나머지 RETURNING 출력 행들을 반환해요. 다시 말해, 모든 RETURNING 절 출력은 모든 데이터베이스 수정 작업이 끝날 때까지 보류돼요.

즉, 문에 RETURNING 절이 포함되어 많은 양의 출력(많은 행 또는 큰 문자열·BLOB 값)을 생성한다면, 그 문은 실행 중에 그 값들을 보관하기 위해 많은 임시 메모리를 사용할 수 있어요.

SQLite는 모든 데이터베이스 변경이 RETURNING 출력이 내보내지기 전에 발생한다는 것은 보장하지만, 개별 RETURNING 행의 순서가 해당 행이 데이터베이스에서 변경된 순서와 일치할 것이라고는 보장하지 않아요. RETURNING 행의 출력 순서는 임의적이며, 내부적으로 행이 처리된 순서와 반드시 관련이 있는 건 아니에요.

2.2. 자기참조 서브쿼리는 불확정적이에요

SQLite는 모든 데이터베이스 변경이 RETURNING 출력이 내보내지기 전에 발생한다는 것을 보장하지만, 데이터베이스 변경이 발생하는 순서나 그러한 변경과 관련해 RETURNING 출력이 언제 계산되는지에 대해서는 보장하지 않아요. RETURNING 절 출력은 모두 첫 번째 sqlite3_step() 호출 중에 계산되어 임시 저장소에 배치되지만, 출력이 계산되는 구체적인 순서와 데이터베이스 변경이 발생하는 순서는 지정되어 있지 않아요. 그 순서는 쿼리마다 달라질 수 있어요.

따라서 RETURNING 출력의 열이 수정 대상 테이블을 참조하는 서브쿼리를 포함한다면, 그 서브쿼리의 결과는 지정되지 않은 동작에 의존할 수 있고, 그래서 쿼리를 호출할 때마다 달라질 수 있어요.

2.3. ACID 변경 사항

앞의 "처리 순서" 섹션에서 "데이터베이스 변경은 첫 번째 sqlite3_step() 호출 중에 발생한다"고 말할 때, 이는 변경 사항이 문을 실행하는 데이터베이스 연결의 비공개 페이지 캐시에 저장된다는 뜻이에요. 변경 사항이 실제로 커밋된다는 뜻은 아니에요. 커밋은 문이 끝날 때까지 발생하지 않고, 문이 더 큰 트랜잭션의 일부라면 그때도 발생하지 않을 수 있어요. 데이터베이스 변경은 여전히 원자성, 일관성, 격리성, 지속성(ACID)을 가져요. 앞의 섹션에서 "변경이 발생한다"고 말할 때는 트랜잭션 커밋을 앞두고 내부 데이터 구조가 조정된다는 의미예요. 그러한 변경 중 일부는 페이지 캐시에 가해지는 압력 정도에 따라 write-ahead log로 흘러 들어갈 수도 있고 그렇지 않을 수도 있어요. 페이지 캐시에 메모리 압박이 없다면, sqlite3_step()이 SQLITE_DONE을 반환한 이후인 트랜잭션 완료 시점까지 디스크에 기록되는 것은 아마 없을 거예요.

다시 말해, 앞의 섹션에서 "데이터베이스 변경이 발생한다"고 말할 때는 문을 실행하는 특정 데이터베이스 연결의 메모리에서 변경이 발생한다는 뜻이지, 변경 사항이 디스크에 기록된다는 뜻은 아니에요.

3. 제한 사항 및 주의 사항

  • RETURNING 절은 가상 테이블(virtual table)에 대한 DELETE 및 UPDATE 문에서는 사용할 수 없어요. 이 제한은 향후 SQLite 버전에서 제거될 수 있어요.

  • RETURNING 절은 최상위 DELETE, INSERT 및 UPDATE 문에서만 사용할 수 있어요. RETURNING 절은 트리거 내부의 문에서는 사용할 수 없어요.

  • RETURNING 절이 포함된 DML 문은 테이블 내용을 반환하지만 서브쿼리로는 사용할 수 없어요. RETURNING 절은 데이터를 애플리케이션에만 반환할 수 있어요. 현재 RETURNING 출력을 다른 테이블이나 쿼리로 돌리는 건 불가능해요. PostgreSQL은 RETURNING 절이 포함된 DML 문을 공통 테이블 표현식(CTE) 안에서 뷰처럼 사용할 수 있어요. SQLite는 현재 그런 기능이 없지만, 향후 릴리스에서 추가될 수 있는 사항이에요.

  • RETURNING 절이 내보내는 행은 임의의 순서로 나타나요. 그 순서는 데이터베이스 스키마, 사용 중인 SQLite의 특정 릴리스, 심지어 같은 문을 실행할 때마다 달라질 수 있어요. 출력 행을 특정 순서로 나타나게 할 방법은 없어요. SQLite가 SQLITE_ENABLE_UPDATE_DELETE_LIMIT 옵션으로 컴파일되어 DELETE 및 UPDATE 문에 ORDER BY 절이 허용되더라도, 그 ORDER BY 절은 RETURNING의 출력 순서를 제약하지 않아요.

  • RETURNING 절이 내보내는 값은 최상위 DELETE, INSERT 또는 UPDATE 문이 보는 값이며, 트리거가 이후에 변경한 값은 반영하지 않아요. 따라서 데이터베이스에 삽입되거나 갱신되는 각 행의 일부 값을 수정하는 AFTER 트리거가 있다면, RETURNING 절은 해당 트리거가 실행되기 전에 계산된 원래 값을 내보내요.

  • RETURNING 절은 최상위 집계 함수(aggregate function)나 윈도우 함수(window function)를 포함할 수 없어요. RETURNING 절에 서브쿼리가 있다면 해당 서브쿼리는 집계 함수와 윈도우 함수를 포함할 수 있지만, 집계 함수가 최상위에 올 수는 없어요.

  • RETURNING 절은 수정 대상 테이블만 참조할 수 있어요. UPDATE FROM 문에서 FROM 절에 명명된 보조 테이블은 RETURNING 절에 포함될 수 없어요.

이 페이지는 2025-05-31 13:08:22Z에 마지막으로 갱신됐어요.

더 알아보기 (Learn more)