테이블의 행을 업데이트하거나 존재하지 않는 경우 INSERT하는 방법은 무엇입니까?
다음과 같은 카운터 테이블이 있습니다.
CREATE TABLE cache (
key text PRIMARY KEY,
generation int
);
카운터 중 하나를 늘리거나 해당 행이 아직 존재하지 않는 경우 0으로 설정하고 싶습니다. 표준 SQL에서 동시성 문제없이이 작업을 수행 할 수있는 방법이 있습니까? 작업은 때때로 트랜잭션의 일부이며 때로는 분리되어 있습니다.
SQL은 가능한 경우 SQLite, PostgreSQL 및 MySQL에서 수정되지 않은 상태로 실행되어야합니다.
검색 결과 동시성 문제가 있거나 데이터베이스에 특정한 몇 가지 아이디어가 나왔습니다.
INSERT
새 행을 시도UPDATE
하고 오류가있는 경우. 불행히도의 오류INSERT
는 현재 트랜잭션 을 중단합니다.UPDATE
행, 수정 된 행이없는 경우INSERT
새 행.MySQL에는
ON DUPLICATE KEY UPDATE
절이 있습니다.
편집 : 모든 훌륭한 답변에 감사드립니다. Paul이 옳은 것처럼 보이며이 작업을 수행 할 수있는 단 하나의 휴대용 방법은 없습니다. 그것은 매우 기본적인 작업처럼 들리기 때문에 저에게 매우 놀랍습니다.
MySQL (및 이후 SQLite)은 REPLACE INTO 구문도 지원합니다.
REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');
이렇게하면 자동으로 기본 키를 식별하고 업데이트 할 일치하는 행을 찾고, 발견되지 않으면 새 행을 삽입합니다.
SQLite는 이미 존재하는 경우 행 교체를 지원 합니다.
INSERT OR REPLACE INTO [...blah...]
이것을 줄여서
REPLACE INTO [...blah...]
이 단축키는 MySQL REPLACE INTO
표현식 과 호환되도록 추가되었습니다 .
다음과 같은 작업을 수행합니다.
INSERT INTO cache VALUES (key, generation)
ON DUPLICATE KEY UPDATE (key = key, generation = generation + 1);
코드 또는 SQL에서 생성 값을 0으로 설정하지만 ON DUP ...를 사용하여 값을 증가시킵니다. 어쨌든 구문이라고 생각합니다.
ON DUPLICATE KEY UPDATE 절은 다음과 같은 이유로 최상의 솔루션입니다. REPLACE는 DELETE 다음에 INSERT를 수행하므로 아주 약간의 기간 동안 레코드가 제거되어 쿼리가 다시 돌아올 수있는 가능성이 아주 적습니다. REPLACE 쿼리 중에 표시됩니다.
나는 INSERT ... ON DUPLICATE UPDATE ...를 선호합니다.
jmoz의 솔루션이 최고입니다. 괄호 대신 SET 구문을 선호하지만
INSERT INTO cache
SET key = 'key', generation = 'generation'
ON DUPLICATE KEY
UPDATE key = 'key', generation = (generation + 1)
;
플랫폼 중립적 인 솔루션을 찾을 수 있을지 모르겠습니다.
이를 일반적으로 "UPSERT"라고합니다.
관련 토론을 참조하십시오.
PostgreSQL에는 병합 명령이 없으며 실제로 작성하는 것은 사소한 일이 아닙니다. 실제로 작업을 "흥미롭게"만드는 이상한 경우가 있습니다.
가장 좋은 (예 : 가능한 가장 많은 조건에서 작업) 접근 방식은 수동 (merge_db)에 표시된 것과 같은 기능을 사용하는 것 입니다.
함수를 사용하고 싶지 않다면 일반적 으로 다음과 같은 방법 으로 벗어날 수 있습니다.
updated = db.execute(UPDATE ... RETURNING 1)
if (!updated)
db.execute(INSERT...)
결함 증명이 아니며 결국 실패 할 것임을 기억하십시오 .
표준 SQL은이 작업에 대한 MERGE 문을 제공합니다. 모든 DBMS가 MERGE 문을 지원하는 것은 아닙니다.
원자 적으로 업데이트하거나 삽입하는 일반적인 방법이없는 경우 (예 : 트랜잭션을 통해) 다른 잠금 체계로 대체 할 수 있습니다. 0 바이트 파일, 시스템 뮤텍스, 명명 된 파이프 등 ...
삽입 트리거를 사용할 수 있습니까? 실패하면 업데이트를 수행하십시오.
If you're OK with using a library that writes the SQL for you, then you can use Upsert (currently Ruby and Python only):
Pet.upsert({:name => 'Jerry'}, :breed => 'beagle')
Pet.upsert({:name => 'Jerry'}, :color => 'brown')
That works across MySQL, Postgres, and SQLite3.
It writes a stored procedure or user-defined function (UDF) in MySQL and Postgres. It uses INSERT OR REPLACE
in SQLite3.
'Development Tip' 카테고리의 다른 글
NSOperation 및 NSOperationQueue 작업 스레드 대 기본 스레드 (0) | 2020.10.06 |
---|---|
JavaScript에서 두 객체 배열의 차이를 얻는 방법 (0) | 2020.10.06 |
ActionLink htmlAttributes (0) | 2020.10.06 |
Eclipse에서 콘솔 창을 여는 방법은 무엇입니까? (0) | 2020.10.06 |
Android Studio를 사용하여 공유 환경 설정 파일을 보려면 어떻게해야합니까? (0) | 2020.10.06 |