programing

UPSERT *삽입 또는 교체하지 않음*

linuxpc 2023. 5. 11. 21:10
반응형

UPSERT *삽입 또는 교체하지 않음*

http://en.wikipedia.org/wiki/Upsert

SQL Server에 저장된 Proc 업데이트 삽입

SQLite에서 이를 수행할 수 있는 현명한 방법이 있습니까?

기본적으로 레코드가 존재한다면 4열 중 3열을 업데이트하고 싶습니다.존재하지 않는 경우 네 번째 열에 대한 기본(NULL) 값의 레코드를 삽입합니다.

ID는 기본 키이므로 UPSERT에는 레코드가 하나만 있습니다.

(분명히 업데이트 또는 삽입이 필요한지 결정하기 위해 선택의 오버헤드를 피하려고 합니다.)

제안?


TABLE CREATE의 SQLite 사이트에서 해당 구문을 확인할 수 없습니다.테스트할 데모를 만들지 않았는데 지원되지 않는 것 같습니다.

만약 그렇다면, 저는 세 개의 열을 가지고 있기 때문에 실제로는 다음과 같이 보일 것입니다.

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    Blob1 BLOB ON CONFLICT REPLACE, 
    Blob2 BLOB ON CONFLICT REPLACE, 
    Blob3 BLOB 
);

하지만 처음 두 블롭은 충돌을 일으키지 않을 것이고, ID만 그럴 것입니다. 그래서 저는 블롭1과 블롭2가 교체되지 않을 것이라고 가정합니다(원하는 대로).


데이터를 바인딩할 때 SQLite의 UPDATES는 완전한 트랜잭션입니다. 즉, 업데이트할 각 행에는 재설정 기능을 사용할 수 있는 INSERT와 달리 준비/바인딩/단계/최종화 문이 필요합니다.

문 개체의 수명은 다음과 같습니다.

  1. sqlite3_prepare_v2()를 사용하여 개체 생성
  2. sqlite3_bind_ 인터페이스를 사용하여 값을 호스트 매개 변수에 바인딩합니다.
  3. sqlite3_step()을 호출하여 SQL을 실행합니다.
  4. sqlite3_reset()을 사용하여 문을 재설정한 다음 2단계로 돌아가서 반복합니다.
  5. sqlite3_finalize()를 사용하여 문 개체를 삭제합니다.

업데이트 INSERT에 비해 느리다고 생각합니다만, 기본 키를 사용하는 SELECT와 비교하면 어떻습니까?

선택 항목을 사용하여 4번째 열(Blob3)을 읽은 다음 REPLACE를 사용하여 원래 4번째 열과 처음 3개 열의 새 데이터를 혼합한 새 레코드를 작성해야 합니까?

표에 ID, NAME, ROLE 등 세 개의 열이 있다고 가정합니다.


불량: 모든 열을 ID=1에 대한 새 값으로 삽입하거나 바꿉니다.

INSERT OR REPLACE INTO Employee (id, name, role) 
  VALUES (1, 'John Foo', 'CEO');

불량: 열 중 2개를 삽입하거나 대체합니다...NAME 열은 NULL 또는 기본값으로 설정됩니다.

INSERT OR REPLACE INTO Employee (id, role) 
  VALUES (1, 'code monkey');

GOOD: SQLite에서 SQLite On 충돌 절 UPSERT 지원사용합니다!UPSERT 구문이 버전 3.24.0으로 SQLite에 추가되었습니다!

UPSERT는 INSERT에 추가된 특수 구문으로, INSERT가 고유 제약 조건을 위반할 경우 INSERT가 UPDATE 또는 no-op로 동작하도록 합니다.UPSERT는 표준 SQL이 아닙니다. SQLite의 UPSERT는 Postgre에서 설정한 구문을 따릅니다.SQL.

여기에 이미지 설명 입력

좋으나 지루함:열 중 2개가 업데이트됩니다.ID=1이 존재할 경우 NAME은 영향을 받지 않습니다.ID=1이 없는 경우 이름은 기본값(NULL)이 됩니다.

INSERT OR REPLACE INTO Employee (id, role, name) 
  VALUES (  1, 
            'code monkey',
            (SELECT name FROM Employee WHERE id = 1)
          );

열 중 2개가 업데이트됩니다.ID=1이 존재할 경우 ROLE은 영향을 받지 않습니다.ID=1이 없는 경우 역할은 기본값이 아닌 '벤치워머'로 설정됩니다.

INSERT OR REPLACE INTO Employee (id, name, role) 
  VALUES (  1, 
            'Susan Bar',
            COALESCE((SELECT role FROM Employee WHERE id = 1), 'Benchwarmer')
          );

INSERT 또는 REPLACE는 "UPSERT"와 동일하지 않습니다.

ID, 이름 및 역할 필드가 있는 Employee 테이블이 있다고 합니다.

INSERT OR REPLACE INTO Employee ("id", "name", "role") VALUES (1, "John Foo", "CEO")
INSERT OR REPLACE INTO Employee ("id", "role") VALUES (1, "code monkey")

붐, 당신은 1번 직원의 이름을 잃어버렸군요.SQLite가 기본값으로 대체되었습니다.

UPSERT의 예상 출력은 역할을 변경하고 이름을 유지하는 것입니다.

기존 행에서 열을 하나 또는 두 개만 보존하려는 경우 Eric B의 대답은 OK입니다.많은 열을 보존하려면 너무 빨리 처리해야 합니다.

여기 양쪽의 열 크기에 상관없이 잘 확장할 수 있는 접근 방식이 있습니다.이를 설명하기 위해 다음 스키마를 가정합니다.

 CREATE TABLE page (
     id      INTEGER PRIMARY KEY,
     name    TEXT UNIQUE,
     title   TEXT,
     content TEXT,
     author  INTEGER NOT NULL REFERENCES user (id),
     ts      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 );

주의할 점은 다음과 같습니다.name행의 입니다. - 행자키입니다운러스연의키.id는 외부 키에만 사용되므로 SQLite가 새 행을 삽입할 때 ID 값 자체를 선택하는 것이 포인트입니다. 기존 행을 해당 에는 다음과 같이 지정합니다.name이전 ID 값(분명히!)을 계속 유지하고 싶습니다.

나는 진실을 성취합니다.UPSERT다음 구성을 사용합니다.

 WITH new (name, title, author) AS ( VALUES('about', 'About this site', 42) )
 INSERT OR REPLACE INTO page (id, name, title, content, author)
 SELECT old.id, new.name, new.title, old.content, new.author
 FROM new LEFT JOIN page AS old ON new.name = old.name;

이 쿼리의 정확한 형식은 약간 다를 수 있습니다.핵심은 사용하는 것입니다.INSERT SELECT왼쪽 외부 조인을 사용하여 기존 행을 새 값에 조인합니다.

, 여서행이존않지았면다하재전,old.id▁▁be 될 것입니다.NULL에는 SQLite에서 ID를 할당합니다. 하지만 이미 그런 행이 있었다면,old.id실제 값을 가지며 이 값은 재사용됩니다.그게 바로 제가 원했던 겁니다.

사실 이것은 매우 유연합니다.사용 방법에 유의하십시오.ts열이 모든 면에서 완전히 누락되었습니다. 열에 다음이 있기 때문입니다.DEFAULT가치, SQLite는 어떤 경우에도 올바른 작업을 수행하므로 제가 직접 처리할 필요가 없습니다.

둘다열을포수있다니습도할함에▁▁on▁both에 열을 .new그리고.old측면을 선택한 후 예를 사용합니다. COALESCE(new.content, old.content)SELECT예를 들어 고정 쿼리를 사용하고 새 값을 자리 표시자와 바인딩하는 경우 "새로운 내용이 있으면 삽입하고, 그렇지 않으면 이전 내용을 유지합니다"라고 말합니다.

이 답변은 업데이트되었으므로 아래 설명은 더 이상 적용되지 않습니다.

2018-05-18 프레스 중지.

SQLite에서 UPSERT 지원!UPSERT 구문이 버전 3.24.0(보류 중)으로 SQLite에 추가되었습니다!

UPSERT는 INSERT에 추가된 특수 구문으로, INSERT가 고유 제약 조건을 위반할 경우 INSERT가 UPDATE 또는 no-op로 동작하도록 합니다.UPSERT는 표준 SQL이 아닙니다. SQLite의 UPSERT는 Postgre에서 설정한 구문을 따릅니다.SQL.

여기에 이미지 설명 입력

또는 다음을 수행합니다.

이를 수행하는 또 다른 방법은 애플리케이션에서 메모리 행을 설정하는 것입니다.긴 아이디.메모리에서 행을 생성할 때 MaxValue. (MaxValue는 ID로 사용되지 않을 것입니다. 충분히 오래 사용할 수ID가 해당 값이 아니므로 이미 데이터베이스에 있어야 하므로 MaxValue이면 UPDATE가 필요하고 삽입해야 합니다.이것은 행을 추적할 수 있는 경우에만 유용합니다.앱의 ID입니다.

만약 당신이 일반적으로 업데이트를 하고 있다면 저는…

  1. 트랜잭션 시작
  2. 업데이트 수행
  3. 행 수 확인
  4. 0이면 삽입을 수행합니다.
  5. 저지르다

만약 당신이 일반적으로 삽입을 하고 있다면 저는 할 것입니다.

  1. 트랜잭션 시작
  2. 삽입 시도
  3. 기본 키 위반 오류 확인
  4. 오류가 발생하면 업데이트를 수행합니다.
  5. 저지르다

이렇게 하면 선택을 피할 수 있고 SQLite에서 트랜잭션에 문제가 없습니다.

저는 이것이 오래된 스레드라는 것을 알고 있지만 최근에 sqlite3에서 작업을 했고 매개 변수화된 쿼리를 동적으로 생성하는 제 요구에 더 적합한 방법을 고안했습니다.

insert or ignore into <table>(<primaryKey>, <column1>, <column2>, ...) values(<primaryKeyValue>, <value1>, <value2>, ...); 
update <table> set <column1>=<value1>, <column2>=<value2>, ... where changes()=0 and <primaryKey>=<primaryKeyValue>; 

아직 업데이트에 where 절이 있는 2개의 쿼리이지만 속임수를 쓰는 것 같습니다.저는 또한 sqlite가 변경()에 대한 호출이 0보다 클 경우 업데이트 문을 완전히 최적화할 수 있다는 비전을 가지고 있습니다.그것이 실제로 그러는지 아닌지는 제가 알 수 없는 일이지만, 사람은 꿈을 꿀 수 없습니까?;)

보너스 포인트의 경우 새로 삽입된 행이든 기존 행이든 행 ID를 반환하는 이 행을 추가할 수 있습니다.

select case changes() WHEN 0 THEN last_insert_rowid() else <primaryKeyValue> end;

버전 3.24.0부터는 SQLite에서 UPSERT가 지원됩니다.

설명서에서 다음을 참조하십시오.

UPSERT는 INSERT에 추가된 특수 구문으로, INSERT가 고유 제약 조건을 위반할 경우 INSERT가 UPDATE 또는 no-op로 동작하도록 합니다. UPSERT는 표준 SQL이 아닙니다. SQLite의 UPSERT는 Postgre에서 설정한 구문을 따릅니다.SQL. UPSERT 구문이 버전 3.24.0(보류)으로 SQLite에 추가되었습니다.

UPSERT는 특수 ON CONCLIVEL 절 뒤에 오는 일반 INSERT 문입니다.

여기에 이미지 설명 입력

이미지 출처: https://www.sqlite.org/images/syntax/upsert-clause.gif


예:

CREATE TABLE t1(id INT PRIMARY KEY, c TEXT);
INSERT INTO t1(id, c) VALUES (1,'a'), (2, 'b');
SELECT * FROM t1;


INSERT INTO t1(id, c) VALUES (1, 'c');
-- UNIQUE constraint failed: t1.id

INSERT INTO t1(id, c) VALUES (1, 'c')
ON CONFLICT DO NOTHING;

SELECT * FROM t1;

INSERT INTO t1(id, c)
VALUES (1, 'c')
ON CONFLICT(id) DO UPDATE SET c = excluded.c;

SELECT * FROM t1;

db<>디플 데모

많은 상황에서 다르게 작동하는 INSERT 또는 REPLACE 대신 UPSERT(UPDATE 또는 INSERT)인 솔루션이 있습니다.

다음과 같이 작동합니다.
동일한 ID의 레코드가 존재하는 경우 업데이트를 시도합니다.
로 인해되지 않은 (으)로 됩니다.NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0)), 합니다.), 레코드를 삽입합니다.

따라서 기존 레코드가 업데이트되었거나 삽입이 수행됩니다.

중요한 세부 사항은 changes() SQL 함수를 사용하여 업데이트 문이 기존 레코드에 도달했는지 확인하고 기록에 도달하지 않은 경우에만 삽입 문을 수행하는 것입니다.

한 가지 언급할 점은 changes() 함수가 하위 레벨 트리거에 의해 수행된 변경을 반환하지 않는다는 것입니다(http://sqlite.org/lang_corefunc.html#changes), 참조). 이 점을 고려해야 합니다.

여기 SQL이 있습니다...

테스트 업데이트:

--Create sample table and records (and drop the table if it already exists)
DROP TABLE IF EXISTS Contact;
CREATE TABLE [Contact] (
  [Id] INTEGER PRIMARY KEY, 
  [Name] TEXT
);
INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
INSERT INTO Contact (Id, Name) VALUES (2, 'John');

-- Try to update an existing record
UPDATE Contact
SET Name = 'Bob'
WHERE Id = 2;

-- If no record was changed by the update (meaning no record with the same Id existed), insert the record
INSERT INTO Contact (Id, Name)
SELECT 2, 'Bob'
WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);

--See the result
SELECT * FROM Contact;

삽입 테스트:

--Create sample table and records (and drop the table if it already exists)
DROP TABLE IF EXISTS Contact;
CREATE TABLE [Contact] (
  [Id] INTEGER PRIMARY KEY, 
  [Name] TEXT
);
INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
INSERT INTO Contact (Id, Name) VALUES (2, 'John');

-- Try to update an existing record
UPDATE Contact
SET Name = 'Bob'
WHERE Id = 3;

-- If no record was changed by the update (meaning no record with the same Id existed), insert the record
INSERT INTO Contact (Id, Name)
SELECT 3, 'Bob'
WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);

--See the result
SELECT * FROM Contact;

Bernhardt의 업데이트:

SQLite에서 업셋을 수행할 수 있습니다. 익숙한 것과는 조금 다를 뿐입니다.다음과 같이 표시됩니다.

INSERT INTO table_name (id, column1, column2) 
VALUES ("youruuid", "value12", "value2")
ON CONFLICT(id) DO UPDATE 
SET column1 = "value1", column2 = "value2"

제가 아는 가장 좋은 방법은 업데이트를 하고 삽입하는 것입니다."선택 항목의 오버헤드"가 필요하지만, 기본 키를 빠르게 검색하기 때문에 큰 부담이 되지 않습니다.

원하는 작업을 수행하려면 테이블 및 필드 이름으로 아래 문을 수정할 수 있어야 합니다.

--first, update any matches
UPDATE DESTINATION_TABLE DT
SET
  MY_FIELD1 = (
              SELECT MY_FIELD1
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
 ,MY_FIELD2 = (
              SELECT MY_FIELD2
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
WHERE EXISTS(
            SELECT ST2.PRIMARY_KEY
            FROM
              SOURCE_TABLE ST2
             ,DESTINATION_TABLE DT2
            WHERE ST2.PRIMARY_KEY = DT2.PRIMARY_KEY
            );

--second, insert any non-matches
INSERT INTO DESTINATION_TABLE(
  MY_FIELD1
 ,MY_FIELD2
)
SELECT
  ST.MY_FIELD1
 ,NULL AS MY_FIELD2  --insert NULL into this field
FROM
  SOURCE_TABLE ST
WHERE NOT EXISTS(
                SELECT DT2.PRIMARY_KEY
                FROM DESTINATION_TABLE DT2
                WHERE DT2.PRIMARY_KEY = ST.PRIMARY_KEY
                );

아리스토텔레스의 대답을 확장하면 더미 '싱글톤' 테이블(단일 행이 있는 자신이 만든 테이블)에서 선택할 수 있습니다.이렇게 하면 일부 중복이 방지됩니다.

또한 MySQL 및 SQLite에서 이 예제를 휴대용으로 보관하고 처음에만 열을 설정할 수 있는 방법의 예로 'date_added' 열을 사용했습니다.

 REPLACE INTO page (
   id,
   name,
   title,
   content,
   author,
   date_added)
 SELECT
   old.id,
   "about",
   "About this site",
   old.content,
   42,
   IFNULL(old.date_added,"21/05/2013")
 FROM singleton
 LEFT JOIN page AS old ON old.name = "about";

누군가가 Cordova의 SQLite에 대한 내 솔루션을 읽고 싶다면 위의 @david 답변 덕분에 일반적인 js 방법을 얻었습니다.

function    addOrUpdateRecords(tableName, values, callback) {
get_columnNames(tableName, function (data) {
    var columnNames = data;
    myDb.transaction(function (transaction) {
        var query_update = "";
        var query_insert = "";
        var update_string = "UPDATE " + tableName + " SET ";
        var insert_string = "INSERT INTO " + tableName + " SELECT ";
        myDb.transaction(function (transaction) {
            // Data from the array [[data1, ... datan],[()],[()]...]:
            $.each(values, function (index1, value1) {
                var sel_str = "";
                var upd_str = "";
                var remoteid = "";
                $.each(value1, function (index2, value2) {
                    if (index2 == 0) remoteid = value2;
                    upd_str = upd_str + columnNames[index2] + "='" + value2 + "', ";
                    sel_str = sel_str + "'" + value2 + "', ";
                });
                sel_str = sel_str.substr(0, sel_str.length - 2);
                sel_str = sel_str + " WHERE NOT EXISTS(SELECT changes() AS change FROM "+tableName+" WHERE change <> 0);";
                upd_str = upd_str.substr(0, upd_str.length - 2);
                upd_str = upd_str + " WHERE remoteid = '" + remoteid + "';";                    
                query_update = update_string + upd_str;
                query_insert = insert_string + sel_str;  
                // Start transaction:
                transaction.executeSql(query_update);
                transaction.executeSql(query_insert);                    
            });
        }, function (error) {
            callback("Error: " + error);
        }, function () {
            callback("Success");
        });
    });
});
}

먼저 다음 기능을 사용하여 열 이름을 선택합니다.

function get_columnNames(tableName, callback) {
myDb.transaction(function (transaction) {
    var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
    transaction.executeSql(query_exec, [], function (tx, results) {
        var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
        var columnNames = [];
        for (i in columnParts) {
            if (typeof columnParts[i] === 'string')
                columnNames.push(columnParts[i].split(" ")[0]);
        };
        callback(columnNames);
    });
});
}

그런 다음 트랜잭션을 프로그래밍 방식으로 빌드합니다.

"값"은 이전에 빌드해야 하는 배열이며 테이블에 삽입하거나 업데이트할 행을 나타냅니다.

"remoteid"는 원격 서버와 동기화하기 때문에 참조로 사용한 ID입니다.

SQLite Cordova 플러그인의 사용은 공식 링크를 참조하십시오.

저는 이것이 당신이 찾고 있는 일 수도 있다고 생각합니다: ON CONCLIVE 조항.

테이블을 다음과 같이 정의하는 경우:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    field1 TEXT 
); 

이제 이미 존재하는 ID로 INSERT를 수행하면 SQLite가 INSERT 대신 자동으로 UPDATE를 수행합니다.

음...

이 방법은 이 질문에 대한 답변에서 나온 몇 가지 다른 방법을 리믹스하고 CTE(Common Table Expressions)의 사용을 통합합니다.질문을 소개하고 제가 왜 그랬는지 설명하겠습니다.

만약 300명의 직원이 있다면 300명의 성을 DAVIS로 바꾸고 싶습니다.그렇지 않으면 새로운 직원을 추가하겠습니다.

테이블 이름: 직원 열: ID, first_name, last_name

쿼리는 다음과 같습니다.

INSERT OR REPLACE INTO employees (employee_id, first_name, last_name)
WITH registered_employees AS ( --CTE for checking if the row exists or not
    SELECT --this is needed to ensure that the null row comes second
        *
    FROM (
        SELECT --an existing row
            *
        FROM
            employees
        WHERE
            employee_id = '300'

        UNION

        SELECT --a dummy row if the original cannot be found
            NULL AS employee_id,
            NULL AS first_name,
            NULL AS last_name
    )
    ORDER BY
        employee_id IS NULL --we want nulls to be last
    LIMIT 1 --we only want one row from this statement
)
SELECT --this is where you provide defaults for what you would like to insert
    registered_employees.employee_id, --if this is null the SQLite default will be used
    COALESCE(registered_employees.first_name, 'SALLY'),
    'DAVIS'
FROM
    registered_employees
;

기본적으로 CTE를 사용하여 기본값을 결정하기 위해 select 문을 사용해야 하는 횟수를 줄였습니다.CTE이므로 테이블에서 원하는 열을 선택하면 INSERT 문에서 이를 사용합니다.

이제 COALESCE 함수에서 null을 값이 무엇이어야 하는지로 대체하여 사용할 기본값을 결정할 수 있습니다.

아리스토텔레스 파갈치스와 그 아이디어를 따르는 것.COALESCEEric B의 답변에 따르면, 여기서는 소수의 열만 업데이트하거나 전체 행이 없는 경우 전체 행을 삽입할 수 있는 업버트 옵션입니다.

이 경우 제목과 내용을 업데이트하여 기존의 다른 이전 값을 유지하고 이름을 찾을 수 없을 때 제공된 값을 삽입해야 한다고 가정합니다.

NOTE id의 경우 강제로 NULL이 됩니다.INSERT자동 증가로 되어 있기 때문에.에는 " 생기키일경우본된"가 .COALESCE또한 사용할 수 있습니다(아리스토리스 파갈치스 주석 참조).

WITH new (id, name, title, content, author)
     AS ( VALUES(100, 'about', 'About this site', 'Whatever new content here', 42) )
INSERT OR REPLACE INTO page (id, name, title, content, author)
SELECT
     old.id, COALESCE(old.name, new.name),
     new.title, new.content,
     COALESCE(old.author, new.author)
FROM new LEFT JOIN page AS old ON new.name = old.name;

따라서 일반적인 규칙은 이전 값을 유지하려면 다음을 사용하는 것입니다.COALESCE값을 업데이트하려면 다음을 사용합니다.new.fieldname

만약 당신이 이것을 두 번의 수술로 하는 것이 괜찮다면요.

단계:

"삽입 또는 무시"로 새 항목 추가

"UPDATE"로 기존 항목 업데이트

두 단계에 대한 입력은 새 항목 또는 업데이트 가능한 항목의 동일한 모음입니다.변경할 필요가 없는 기존 항목에서 올바르게 작동합니다.업데이트되지만 동일한 데이터로 업데이트되므로 최종 결과는 변경되지 않습니다.

물론, 천천히 등.비효율적입니다.네.

SQL을 작성하고 유지관리하고 이해하기가 쉽습니까?물론입니다.

그것은 고려해야 할 절충안입니다.작은 이변에도 잘 작동합니다.코드 유지 관리를 위해 효율성을 희생하는 것을 꺼리지 않는 사용자에게 매우 적합합니다.

WHERE를 사용하여 최신 날짜 레코드를 선택하는 완전한 예제입니다.

-- https://www.db-fiddle.com/f/7jyj4n76MZHLLk2yszB6XD/22
 
DROP TABLE IF EXISTS db;

CREATE TABLE db
(
 id PRIMARY KEY,
 updated_at,
 other
);

-- initial INSERT
INSERT INTO db (id,updated_at,other) VALUES(1,1,1);

SELECT * FROM db;

-- INSERT without WHERE
INSERT INTO db (id,updated_at,other) VALUES(1,2,2)
ON CONFLICT(id) DO UPDATE SET updated_at=excluded.updated_at;

SELECT * FROM db;

-- WHERE is FALSE
INSERT INTO db (id,updated_at,other) VALUES(1,2,3)
ON CONFLICT(id) DO UPDATE SET updated_at=excluded.updated_at, other=excluded.other
WHERE excluded.updated_at > updated_at;

SELECT * FROM db;

-- ok to SET a PRIMARY KEY. WHERE is TRUE
INSERT INTO db (id,updated_at,other) VALUES(1,3,4)
ON CONFLICT(id) DO UPDATE SET id=excluded.id, updated_at=excluded.updated_at, other=excluded.other
WHERE excluded.updated_at > updated_at;

SELECT * FROM db;

방금 이 스레드를 읽고 이 "UPSERT" 노래만 하기가 쉽지 않다는 것에 실망한 후, 저는 더 자세히 조사했습니다.

실제로 SQLITE에서 이 작업을 직접적이고 쉽게 수행할 수 있습니다.

다음을 사용하는 대신:INSERT INTO

사용:INSERT OR REPLACE INTO

이것은 정확히 당신이 원하는 것을 합니다!

SELECT COUNT(*) FROM table1 WHERE id = 1;

한다면COUNT(*) = 0

INSERT INTO table1(col1, col2, cole) VALUES(var1,var2,var3);

그렇지 않으면COUNT(*) > 0

UPDATE table1 SET col1 = var4, col2 = var5, col3 = var6 WHERE id = 1;

언급URL : https://stackoverflow.com/questions/418898/upsert-not-insert-or-replace

반응형