SQLite-向上插入*不是*插入或替换
在SQLite中是否有一些我没有想到的聪明方法可以做到这一点 基本上我想更新四列中的三列如果记录存在, 如果它不存在,我想在第四列插入默认(NUL)值的记录 ID是主键,因此只有一条记录需要上传 (我试图避免SELECT的开销,以确定是否需要更新或插入) 建议SQLite-向上插入*不是*插入或替换,sql,sqlite,upsert,Sql,Sqlite,Upsert,在SQLite中是否有一些我没有想到的聪明方法可以做到这一点 基本上我想更新四列中的三列如果记录存在, 如果它不存在,我想在第四列插入默认(NUL)值的记录 ID是主键,因此只有一条记录需要上传 (我试图避免SELECT的开销,以确定是否需要更新或插入) 建议 我无法确认SQLite站点上用于表创建的语法。 我还没有建立一个演示来测试它,但它似乎不受支持 如果是的话,我有三列,所以它实际上看起来像: CREATE TABLE table1( id INTEGER PRIMARY KE
我无法确认SQLite站点上用于表创建的语法。 我还没有建立一个演示来测试它,但它似乎不受支持 如果是的话,我有三列,所以它实际上看起来像:
CREATE TABLE table1(
id INTEGER PRIMARY KEY ON CONFLICT REPLACE,
Blob1 BLOB ON CONFLICT REPLACE,
Blob2 BLOB ON CONFLICT REPLACE,
Blob3 BLOB
);
但是前两个blob不会引起冲突,只有ID会引起冲突
因此,我假设Blob1和Blob2不会被替换(根据需要)
当绑定数据是一个完整事务时,在SQLite中进行更新,这意味着 要更新的每个发送行都需要:Prepare/Bind/Step/Finalize语句 与允许使用重置功能的插入不同 语句对象的生命周期如下所示:
CREATE TABLE table1(
id INTEGER PRIMARY KEY ON CONFLICT REPLACE,
field1 TEXT
);
也许我应该使用select读取第4列(Blob3),然后使用REPLACE编写一条新记录,将原始第4列与前3列的新数据混合在一起?我知道的最佳方法是进行更新,然后插入。 “选择的开销”是必要的,但这不是一个可怕的负担,因为您正在快速搜索主键 您应该能够使用表名和字段名修改以下语句,以执行所需操作
--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
);
我想这可能就是你想要的: 如果您这样定义表:
CREATE TABLE table1(
id INTEGER PRIMARY KEY ON CONFLICT REPLACE,
field1 TEXT
);
现在,如果您使用已经存在的id进行插入,SQLite会自动进行更新,而不是插入
Hth…如果您一般都在做更新,我会
如果你一般都做插页,我会
这样,您就避免了select,并且在Sqlite上事务性地表现良好 刚读了这篇文章,对这篇文章的“升级”并不容易感到失望,我进一步调查了 实际上,您可以在SQLITE中直接轻松地完成这项工作 而不是使用:
插入到
使用:插入或替换到
这正是你想要它做的 插入或替换不等同于“向上插入”
假设我拥有具有字段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已将其替换为默认值
INSERT OR REPLACE INTO Employee (id, name, role)
VALUES ( 1,
'Susan Bar',
COALESCE((SELECT role FROM Employee WHERE id = 1), 'Benchwarmer')
);
UPSERT的预期输出是更改角色并保留名称。假设表中有三列:ID、name和role
错误:这将插入所有列,或用ID=1的新值替换所有列:
INSERT OR REPLACE INTO Employee (id, name, role)
VALUES (1, 'John Foo', 'CEO');
错误:这将插入或替换2列。。。“名称”列将设置为NULL或默认值:
INSERT OR REPLACE INTO Employee (id, role)
VALUES (1, 'code monkey');
好:在冲突子句上使用SQLite UPSERT语法已添加到版本为3.24.0的SQLite中 UPSERT是对INSERT的特殊语法添加,如果INSERT违反唯一性约束,则会导致INSERT表现为更新或NOOP。UPSERT不是标准的SQL。SQLite中的UPSERT遵循PostgreSQL建立的语法 很好但很乏味:这将更新其中的两列。 当ID=1存在时,名称将不受影响。 当ID=1不存在时,名称将是默认值(NULL) 这将更新其中的两列。 当ID=1存在时,角色将不受影响。 当ID=1不存在时,角色将设置为“Benchwarmer”,而不是默认值
INSERT OR REPLACE INTO Employee (id, name, role)
VALUES ( 1,
'Susan Bar',
COALESCE((SELECT role FROM Employee WHERE id = 1), 'Benchwarmer')
);
我意识到这是一个旧线程,但我最近一直在使用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>;
插入或忽略(、、…)值(、…);
更新集=,=。。。其中changes()=0和=;
更新时仍然有2个查询带有where子句,但似乎做到了这一点。我脑子里也有这样的想法,如果对changes()的调用大于零,sqlite可以完全优化update语句。我不知道这是否真的会发生,但一个人可以做梦,不是吗
对于奖励积分,您可以附加此行,该行返回您的行id,无论是新插入的行还是现有行
select case changes() WHEN 0 THEN last_insert_rowid() else <primaryKeyValue> end;
在0时选择case changes(),然后选择last_insert_rowid(),否则结束;
如果只想保留现有行中的一列或两列,则可以。如果您想保留大量列,那么很快就会变得太麻烦
这里有一种方法可以很好地扩展到任意数量的列。为了说明这一点,我将采用以下模式:
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值。但是,当根据现有行的名称
更新该行时,我希望它同时
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";
--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;
SELECT COUNT(*) FROM table1 WHERE id = 1;
INSERT INTO table1(col1, col2, cole) VALUES(var1,var2,var3);
UPDATE table1 SET col1 = var4, col2 = var5, col3 = var6 WHERE id = 1;
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
;
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);
});
});
}
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;
INSERT INTO table_name (id, column1, column2)
VALUES ("youruuid", "value12", "value2")
ON CONFLICT(id) DO UPDATE
SET column1 = "value1", column2 = "value2"
-- 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;