DELETE 문

DELETE 문

DELETE 명령은 table-name으로 식별되는 테이블에서 레코드를 제거합니다. WHERE 절이 없으면 테이블의 모든 레코드가 삭제되고, WHERE 절이 있으면 그 조건식이 참인 행만 삭제됩니다. 이 페이지에서는 DELETE 문의 구문과 동작을 설명합니다.

출처: 문서

본문

1. 개요

delete-stmt:

WITH RECURSIVE common-table-expression , DELETE FROM qualified-table-name returning-clause expr WHERE

common-table-expression:

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

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

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

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

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 -

qualified-table-name:

schema-name . table-name AS alias INDEXED BY index-name NOT INDEXED

returning-clause:

RETURNING expr AS column-alias * ,

DELETE 명령은 qualified-table-name으로 식별되는 테이블에서 레코드를 삭제해요.

WHERE 절이 없으면 테이블의 모든 레코드가 삭제돼요. WHERE 절이 있으면, WHERE 절의 불리언 표현식이 true인 행만 삭제돼요. 표현식이 false이거나 NULL인 행은 유지돼요.

2. CREATE TRIGGER 내 DELETE 문의 제한

다음 제한 사항은 CREATE TRIGGER 문 본문 안에 나타나는 DELETE 문에 적용돼요.

  • 트리거 본문 안의 DELETE 문 일부로 지정되는 table-name은 정규화되지 않아야 해요. 즉, 테이블 이름 앞의 schema-name. 접두어는 트리거 안에서 허용되지 않아요. 트리거가 연결된 테이블이 temp 데이터베이스에 있지 않다면, 트리거 본문 안의 DELETE 문은 같은 데이터베이스 안의 테이블에 대해 동작해야 해요. 트리거가 연결된 테이블이 TEMP 데이터베이스에 있다면, 삭제 대상 테이블의 정규화되지 않은 이름은 최상위 문에서와 같은 방식으로 확인돼요 (먼저 TEMP 데이터베이스, 그다음 main 데이터베이스, 그다음 연결된 순서대로 다른 데이터베이스들을 검색해요).

  • 트리거 안에서는 DELETE 문에 INDEXED BY 및 NOT INDEXED 절을 사용할 수 없어요.

  • LIMIT 및 ORDER BY 절(아래에서 설명)은 트리거 안의 DELETE 문에서 지원되지 않아요.

  • RETURNING 절은 트리거에서 지원되지 않아요.

3. 선택적 LIMIT 및 ORDER BY 절

SQLite가 SQLITE_ENABLE_UPDATE_DELETE_LIMIT 컴파일 타임 옵션으로 컴파일되면, DELETE 문의 구문은 선택적 ORDER BY 및 LIMIT 절이 추가되어 확장돼요.

delete-stmt-limited:

WITH RECURSIVE common-table-expression , DELETE FROM qualified-table-name WHERE expr returning-clause ORDER BY ordering-term , LIMIT expr OFFSET expr , expr

DELETE 문에 LIMIT 절이 있으면, 삭제될 최대 행 수는 수반된 표현식을 평가하고 정수 값으로 캐스팅해서 구해요. LIMIT 절의 평가 결과를 무손실로 정수 값으로 변환할 수 없으면 오류예요. 음수 LIMIT 값은 '제한 없음'으로 해석돼요. DELETE 문에 OFFSET 절도 있으면 마찬가지로 평가되고 정수 값으로 캐스팅돼요. 역시 값을 무손실로 정수로 변환할 수 없으면 오류예요. OFFSET 절이 없거나 계산된 정수 값이 음수이면 유효 OFFSET 값은 0이에요.

DELETE 문에 ORDER BY 절이 있으면, LIMIT 절이 없을 때 삭제되었을 모든 행이 ORDER BY에 따라 정렬돼요. OFFSET 절 표현식을 평가해서 얻은 값인 M개의 첫 행은 건너뛰고, 그다음 LIMIT 표현식의 값인 N개가 삭제돼요. OFFSET 절을 고려한 뒤 남은 행이 N개보다 적거나 LIMIT 절이 음수 값으로 평가되면 남은 모든 행이 삭제돼요.

DELETE 문에 ORDER BY 절이 없으면, LIMIT 절이 없을 때 삭제되었을 모든 행이 임의의 순서로 모이고, 실제로 삭제될 부분 집합을 결정하기 위해 LIMIT 및 OFFSET 절이 적용돼요.

DELETE 문의 ORDER BY 절은 어떤 행이 LIMIT 안에 들어가는지 결정하는 데만 사용돼요. 행이 삭제되는 순서는 임의적이며 ORDER BY 절의 영향을 받지 않아요. 즉, RETURNING 절이 있으면 문이 반환하는 행은 ORDER BY 절로 지정된 순서가 아닐 가능성이 높아요.

Truncate 최적화

DELETE 문에서 WHERE 절과 RETURNING 절이 모두 생략되고 삭제 대상 테이블에 트리거가 없으면, SQLite는 테이블의 각 행을 개별적으로 방문하지 않고 전체 테이블 내용을 지우는 최적화를 사용해요. 이 'truncate' 최적화는 삭제를 훨씬 빠르게 실행해요. SQLite 3.6.5(2008-11-12) 이전 버전에서는 truncate 최적화로 인해 sqlite3_changes() 및 sqlite3_total_changes() 인터페이스와 count_changes pragma가 실제 삭제된 행 수를 반환하지 않았어요. 이 문제는 3.6.5(2008-11-12) 버전에서 수정됐어요.

truncate 최적화는 SQLITE_OMIT_TRUNCATE_OPTIMIZATION 컴파일 타임 스위치로 SQLite를 다시 컴파일하면 모든 쿼리에 대해 영구적으로 비활성화할 수 있어요.

truncate 최적화는 런타임에 sqlite3_set_authorizer() 인터페이스를 사용해서도 비활성화할 수 있어요. authorizer 콜백이 SQLITE_DELETE 동작 코드에 대해 SQLITE_IGNORE를 반환하면 DELETE 작업은 진행되지만 truncate 최적화는 우회되고 행이 하나씩 삭제돼요.

이 페이지는 2025-05-31 13:08:22Z에 마지막으로 업데이트되었어요.

더 알아보기 (Learn more)