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

在SQL Server上插入更新存储的过程

在SQLite中有一些聪明的方法可以做到这一点,但我还没有想到了吗?

基本上,如果记录存在,我想更新四列中的三列,
如果不存在,我想使用默认(NUL)值插入记录第四列。

ID是主键,因此UPSERT将永远只有一条记录。

(我试图避免SELECT的开销来确定如果我需要显式地进行UPDATE或INSERT)

建议?


我不能确认TABLE CREATE的SQLite站点上的语法。
我有没有构建用于测试的演示,但似乎不受支持。.

如果有的话,我有三列,因此实际上看起来像: br />
,但是前两个blob不会引起冲突,仅ID会
,所以我不会按需要替换asusme Blob1和Blob2

当绑定数据是一个完整的事务时,SQLite中的更新,这意味着
每个要更新的发送行都需要:Prepare / Bind / Step / Finalize语句
与INSERT不同允许使用重置功能

语句对象的寿命如下:


使用sqlite3_prepare_v2()创建对象
使用sqlite3_bind_接口将值绑定到主机参数。 sqlite3_finalize()。

UPDATE我想与INSERT相比,它比较慢,但是与使用主键的SELECT相比,它又如何呢?

也许我应该使用select来读取第4列(Blob3),然后使用REPLACE编写一条新记录,将原始的第4列与前3列的新数据混合在一起?

评论

预发行版本中提供的SQLite-UPSERT请参阅:sqlite.1065341.n5.nabble.com/…

在SQLite 3.24.0版本中可用的UPSERT

#1 楼

假设表中有三列:ID,NAME,ROLE


BAD:这将用ID = 1的新值插入或替换所有列:




BAD:这将插入或替换2列... NAME列将设置为NULL或默认值:

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



好:在冲突子句中使用SQLite
SQLite中的UPSERT支持! UPSERT语法已在3.24.0版本中添加到SQLite中! 。 UPSERT不是标准的SQL。 SQLite中的UPSERT遵循PostgreSQL建立的语法。



很好,但很容易:它将更新2列。
当ID = 1时,名称将不受影响。 ID = 1不存在,名称为默认值(NULL)。

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


这将更新2列。
当ID = 1时
当ID = 1不存在时,角色将设置为'Benchwarmer',而不是默认值。

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


评论


+1辉煌!如果需要合并/比较任何字段的旧值和新值,则内嵌的select子句使您可以灵活地覆盖默认的ON CONFLICT REPLACE功能。

– G__
2011年4月1日在16:56

如果“雇员”被级联删除的其他行引用,则其他行仍将被替换删除。

–唐·雷巴(Don Reba)
2011年8月3日,9:29

最后一个查询不正确。应该是:coalesce((从Employee中选择id = 1的角色,'Benchwarmer')

–越南
11年11月21日在1:09



您能解释一下为什么这将用ID = 1的新值插入或替换所有列:在第一个示例中被认为是BAD吗?您在此处显示的命令旨在创建一个ID为1的新记录,命名为John Foo并担任角色CEO,或者使用该数据覆盖ID为1的记录(如果该记录已经存在)(假定id是主键) 。那么,如果真的发生这种情况,那为什么不好呢?

– O. R. Mapper
2014年1月4日在22:03



@Cornelius:很明显,但这不是第一个示例中发生的情况。第一个示例旨在强制设置所有列,无论插入记录还是替换记录,这都是事实。那么,为什么认为这不好呢?链接的答案还仅指出了为什么在指定列的子集时会发生不良情况,例如第二个示例;指定所有列的值时,似乎并没有详细说明第一个示例INSERT或REPLACE中发生的任何不良影响。

– O. R. Mapper
2014年1月26日10:07



#2 楼

INSERT OR REPLACE不等同于“ UPSERT”。 /> B,您已经丢失了员工编号1的名称。SQLite已将其替换为默认值。

UPSERT的预期输出将是更改角色并保留姓名。

评论


这是针对ruby的upsert库和针对python的upsert库

– Seamus Abshere
2012年11月26日17:31

但确实如此,对具有两列(无null)的表进行INSERT或REPLACE等效于UPSERT。

– QED
13年6月21日在18:15

同意,这不是100%的upsert,但在上述某些情况下可以喜欢它。因此,程序员将需要做出自己的判断。

– Gilco
2015年9月1日在1:02



@QED否,因为delete + insert(这是一个替换)是2个dml语句,例如带有自己的触发器。它仅与1条更新语句不同。

– Sebas
16年2月9日,下午1:43

#3 楼

如果您只想保留现有行中的一列或两列,那么Eric B的答案是可以的。如果您想保留很多列,那么它会变得太麻烦了。

这里的方法可以很好地扩展到任何一侧的任意数量的列。为了说明这一点,我将假设以下模式:

 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值(很明显!)。 br />
 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;


此查询的确切形式可能有所不同。关键是将UPSERT与左外部联接一起使用,以将现有行联接到新值。

此处,如果以前不存在任何行,则INSERT SELECT将为old.id,然后SQLite将进行赋值一个ID,但如果已经有这样的行,则NULL将具有实际值,并将其重用。这正是我想要的。

实际上,这非常灵活。请注意,old.id列在所有方面都是完全缺失的-因为它具有ts值,所以SQLite在任何情况下都将做正确的事情,因此我不必自己照顾它。

您还可以在DEFAULTnew的两边都包含一列,然后使用在外部old中说“如果有,则插入新内容,否则保留旧内容” –例如如果您使用固定查询并将新值与占位符绑定。

评论


+1效果很好,但是在SELECT ... AS旧的条件上添加WHERE name =“ about”约束以加快处理速度。如果您有1m +行,这将非常慢。

–user918938
2013年4月14日4:43在

好点,您的评论+1。不过,我将其排除在答案之外,因为添加这样的WHERE子句只需要我在想出这种方法时首先要消除的那种查询冗余。像往常一样:在需要性能的情况下,可以对查询的结构进行非规范化(在这种情况下)。

–亚里斯多德·帕加尔兹(Aristotle Pagaltzis)
13年4月27日在22:02

如果需要,可以简化aristotle的示例:INSERT或REPLACE INTO页面(id,名称,标题,内容,作者)SELECT id,“关于”,“关于此站点”,内容42 FROM(选择NULL)左联接(SELECT * FROM page WHERE name ='about')

– jcox
16年8月18日在15:07



在执行替换(即更新)时,这是否会不必要地触发ON DELETE触发器?

–卡拉库里
17年1月20日18:00



它肯定会触发ON DELETE触发器。邓诺关于不必要的。对于大多数用户而言,这可能是不必要的,甚至是不必要的,但可能并非对所有用户而言。同样,由于它还会将带有外键的任何行级联删除到所讨论的行中,这可能是许多用户遇到的问题。不幸的是,SQLite与真正的UPSERT几乎没有任何关系。 (我猜是用INSTEAD OF UPDATE触发器伪造它的。)

–亚里斯多德·帕加尔兹(Aristotle Pagaltzis)
17-2-19在6:02



#4 楼

如果您通常要进行更新,我会..


开始交易
进行更新
检查行数
如果为0,则执行插入
提交

如果您通常在进行插入操作,我会


开始交易
尝试插入操作
检查主插入密钥冲突错误
如果遇到错误,请执行更新
提交

这种方式可以避免选择,并且在Sqlite上具有事务性。

评论


如果要在第三步使用sqlite3_changes()检查行数,请确保不要使用多个线程的数据库句柄进行修改。

–亚麻蛋白
2010年7月2日在17:31

下列内容是否会带来同样的效果:1)选择id ='x'的id表格2)如果(ResultSet.rows.length == 0)更新id ='x'的表格;

–弗洛林
2010年7月12日在1:23

如何进行批量插入/更新?一次一次就可以了。

–迈克尔·加贝(Michael Gabay)
18年5月10日在16:14

#5 楼

该答案已更新,因此下面的注释不再适用。

2018-05-18 STOP PRESS。

SQLite中的UPS支持! UPSERT语法已从3.24.0版(待定)添加到SQLite中!

UPSERT是INSERT的一种特殊语法添加,如果INSERT违反,则会导致INSERT表现为UPDATE或no-op。唯一性约束。 UPSERT不是标准的SQL。 SQLite中的UPSERT遵循PostgreSQL建立的语法。

另一种方式:

另一种完全不同的方法是:在我的应用程序中,我将内存中的rowID设置为long.MaxValue当我在内存中创建行时。 (MaxValue永远不会用作ID,您的寿命将不够长...。然后,如果rowID不是该值,则它必须已经存在于数据库中,因此如果它是MaxValue,则需要进行UPDATE,然后需要插入。仅当您可以在应用程序中跟踪rowID时,此功能才有用。

评论


INSERT INTO table(...)SELECT ... WHERE changes()= 0;为我工作。

– Manuel Lopera
16-10-5在15:44

不错,很简单,但是在更新和插入之间删除该行时具有竞争条件,不是吗?

– w00t
16年11月9日在13:21

@ w00t如果在事务中运行此命令怎么办?

– copolii
16年9月9日在21:48

@copolii实际上不确定这是否足够,也许应该锁定该行?

– w00t
16年11月10日在14:08

这就是nodejs sqlite-upsert模块的工作方式。 github.com/pbrandt1/sqlite3-upsert/blob/master/index.js

– phyatt
17年5月5日在15:52

#6 楼

我意识到这是一个旧线程,但是最近我一直在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>; 


仍然是2个查询,其中包含关于更新的where子句,但似乎可以解决问题。我脑中也有这样的想法:如果对changes()的调用大于零,则sqlite可以完全优化更新语句。这是否真的超出了我的能力,但是一个人可以做梦,不是吗? ;)

要获得奖励积分,可以添加此行,无论是新插入的行还是现有的行,都将返回该行的ID。

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


#7 楼

这是一个实际上是UPSERT(更新或INSERT)而不是INSERT或REPLACE(在许多情况下工作原理不同)的解决方案。

它的工作原理如下:
1。如果存在具有相同ID的记录,请尝试更新。
2。如果更新未更改任何行(NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0)),则插入记录。

因此更新了现有记录或将执行插入。

重要细节是使用SQL()函数检查update语句是否命中任何现有记录,并且仅在未命中任何记录时才执行insert语句。

要提到的一件事是,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;


评论


对于我来说,这似乎是比Eric更好的解决方案。但是在INSERT INTO Contact(Id,Name)SELECT 3中,'Bob'WHERE changes()= 0;应该也可以。

–bkausbk
2015年2月2日,12:12



#8 楼

从SQLite 3.24.0版本开始,SQLite支持UPSERT。如果INSERT违反唯一性约束。 UPSERT不是标准的SQL。 SQLite中的UPSERT遵循PostgreSQL建立的语法。 UPSERT语法已在3.24.0版(待定)中添加到SQLite中。 :https://www.sqlite.org/images/syntax/upsert-clause.gif

评论


截至API 27为止,Android仍为3.19

– Brill Pappin
9月9日15:31

#9 楼

Bernhardt的更新:
您确实可以在SQLite中进行upsert,它看起来与您以前的习惯有所不同。它看起来像:
INSERT INTO table_name (id, column1, column2) 
VALUES ("youruuid", "value12", "value2")
ON CONFLICT(id) DO UPDATE 
SET column1 = "value1", column2 = "value2"


评论


这实际上是错误的。应该是这样的:INSERT INTO table_name(id,column1,column2)VALUES(123,'value1','value2')ON CONFLICT(id)DO UPDATE SET column1 ='value1',column2 ='value2'

– Bernhardt Scherer
11月20日12:58



是的,我知道,插入内容也需要ID。我将对其进行修改,使其更正确。也喜欢ID上的冲突。

– Brill Pappin
11月20日19:11



#10 楼

您可以从虚拟的“单身”表(您自己创建的表中包含一行)中进行选择,以扩展亚里士多德的答案。这样可以避免某些重复。

我还将示例保留在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";


#11 楼

我知道最好的方法是先进行更新,然后进行插入。
“选择的开销”是必要的,但这并不是一个沉重的负担,因为您正在搜索主键,这很快。

您应该可以使用表和字段名称修改以下语句以执行所需的操作。

--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
                );


评论


我认为这不是一个好主意,因为您需要对数据库引擎执行两次请求。

–里卡多(Ricardo da Rocha)Vitor
18年11月15日在12:57

#12 楼

如果有人想在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, '').split(','); ///// RegEx
        var columnNames = [];
        for (i in columnParts) {
            if (typeof columnParts[i] === 'string')
                columnNames.push(columnParts[i].split(" ")[0]);
        };
        callback(columnNames);
    });
});
}


然后以编程方式构建事务。

“ Values”是您应该在其之前构建的数组,它表示要插入或更新到表中的行。

“ remoteid”是我用作的ID参考,因为我正在与远程服务器同步。

有关SQLite Cordova插件的使用,请参阅官方链接

#13 楼

此方法重新混合了该问题答案中的其他几种方法,并结合使用了CTE(公用表表达式)。我将介绍该查询,然后解释我为什么做我的工作。

如果有雇员300,我想将雇员300的姓氏更改为DAVIS。否则,我将添加一个新雇员。

表名称:employees
列:id,名字,姓氏

查询是:

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函数中通过替换空值来决定要使用的默认值值应该是什么。

#14 楼

遵循亚里斯多德·帕加尔齐斯(Aristotle Pagaltzis)和Eric B的回答COALESCE的想法,这里是一个upsert选项,仅更新几列或如果不存在则插入整行。在这种情况下,想象一下标题和应该更新内容,保留其他旧值(如果存在),并在找不到名称时插入提供的值:

注意id被强制为NULL,因为它应该是自动递增的。如果只是生成的主键,则也可以使用INSERT(请参阅Aristotle Pagaltzis注释)。

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,要更新值时,请使用COALESCE

评论


自动增量密钥肯定会导致COALESCE(old.id,new.id)错误。虽然“保持大多数行不变(除了缺少值的地方)”实际上听起来像是一个用例,但我认为这并不是人们在寻找如何进行UPSERT时要寻找的东西。

–亚里斯多德·帕加尔兹(Aristotle Pagaltzis)
17年12月31日在22:28

@AristotlePagaltzis道歉,如果我错了,我没有使用自动增量。我在此查询中寻找的是仅更新少量列或在不存在的情况下使用提供的值插入整行。我一直在处理您的查询,但在插入时却无法实现:从旧表中选择的列分配给NULL,而不分配给新提供的值。这就是使用COALESCE的原因。我不是sqlite的专家,我一直在测试此查询,并且似乎可以解决问题,如果您能通过自动增量将其指向解决方案,我将非常感谢

– Miquel
18年1月2日在13:12

如果是自动递增键,则要插入NULL作为键,因为这会告诉SQLite改为插入下一个可用值。

–亚里斯多德·帕加尔兹(Aristotle Pagaltzis)
18年1月3日在16:38

我并不是说您不应该做自己正在做的事情(如果您需要它,那么您就需要它),只是这并不是对这个问题的真正答案。 UPSERT通常意味着您要在表中存储一行,而只是不知道是否已有匹配的行可将值放入其中或需要将其作为新行插入。您的用例是,如果您已经有一个匹配的行,则希望忽略新行中的大多数值。很好,这不是所问的问题。

–亚里斯多德·帕加尔兹(Aristotle Pagaltzis)
18年1月3日在17:12

#15 楼

我认为这可能是您要寻找的:ON CONFLICT子句。

如果您这样定义表:如果您使用已经存在的ID进行INSERT,则SQLite会自动进行UPDATE而不是INSERT。

Hth ...

评论


我认为这行不通,它将清除插入语句中缺少的列

– Sam Saffron
09年1月7日,下午2:25

@Mosor:对不起我-1。这与发出REPLACE语句相同。

– Alix Axel
2010-4-27的0:04

-1,因为它执行删除操作,如果主键已经存在,则执行插入操作。

–frast
2010年5月18日在7:13

#16 楼

如果您不介意在两个操作中执行此操作。

步骤:

1)使用“ INSERT OR IGNORE”添加新项目

2 )使用“ UPDATE”更新现有项目。

两个步骤的输入是相同的新项目或可更新项目的集合。适用于不需要更改的现有项目。它们将被更新,但是具有相同的数据,因此最终结果将保持不变。

确定,较慢等。效率低下。是的。

易于编写sql并维护和理解它吗?绝对是

这是一个需要权衡的问题。
非常适合小型upsert。非常适合那些不介意牺牲代码可维护性效率的人。

评论


所有人注意:INSERT OR REPLACE不是本文的目的。 INSERT OR REPLACE将在您的表中创建一个具有新ID的NEW行。那不是更新。

–sapbucket
1月5日23:50

#17 楼

刚读完该线程后,对仅进行此“ UPSERT”操作感到失望,我进一步进行了调查... />
而不是使用:INSERT INTO

使用:INSERT OR REPLACE INTO

这正是您想要的功能!

评论


-1 INSERT OR REPLACE不是UPSERT。有关原因,请参见gregschlom的“答案”。埃里克B(Eric B)的解决方案实际可行,需要一些支持。

–天
2011年7月13日在22:49

#18 楼

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


if COUNT(*) = 0

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


if COUNT(*) > 0

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


评论


这太复杂了,SQL可以在一个查询中很好地处理

–罗宾·坎特斯(Robin Kanters)
16 Jan 18 '14:31