myu*_*suf 14 sql postgresql knex.js
我在PostgreSQL中有一个upsert查询,如:
INSERT INTO table
(id, name)
values
(1, 'Gabbar')
ON CONFLICT (id) DO UPDATE SET
name = 'Gabbar'
WHERE
table.id = 1
Run Code Online (Sandbox Code Playgroud)
我需要使用knex来进行此upsert查询.怎么去这个?
因此,我使用Dotnil在Knex问题页面上的回答中的以下建议解决了这一问题:
var data = {id: 1, name: 'Gabbar'};
var insert = knex('table').insert(data);
var dataClone = _.cloneDeep(data);
delete dataClone.id;
var update = knex('table').update(dataClone).whereRaw('table.id = ' + data.id);
var query = util.format('%s ON CONFLICT (id) DO UPDATE SET %s',
insert.toString(),
update.toString().replace(/^update\s.*\sset\s/i, '')
);
return knex.raw(query)
.then(function(dbRes){
// stuff
});
Run Code Online (Sandbox Code Playgroud)
希望这对某人有帮助。
我为此创建了一个函数,并在 knex github 问题页面上对其进行了描述(以及处理复合唯一索引的一些问题)。
const upsert = (params) => {
const {table, object, constraint} = params;
const insert = knex(table).insert(object);
const update = knex.queryBuilder().update(object);
return knex.raw(`? ON CONFLICT ${constraint} DO ? returning *`, [insert, update]).get('rows').get(0);
};
Run Code Online (Sandbox Code Playgroud)
用法示例:
const objToUpsert = {a:1, b:2, c:3}
upsert({
table: 'test',
object: objToUpsert,
constraint: '(a, b)',
})
Run Code Online (Sandbox Code Playgroud)
如果你有一个复合索引 (a,b) 并且 b 可以为空,那么值 (1, NULL) 和 (1, NULL) 被 Postgres 认为是相互唯一的(我也不明白)。
从knex@v0.21.10+onConflict开始,引入了一种新方法。
官方文档说:
为 PostgreSQL、MySQL 和 SQLite 数据库实现。插入查询的修饰符,用于指定发生冲突时的替代行为。当表具有 PRIMARY KEY 或 UNIQUE 索引(或一组列的复合索引)并且被插入的行与那些列中表中已存在的行具有相同的值时,就会发生冲突( s)。发生冲突时的默认行为是引发错误并中止查询。使用此方法,您可以将此行为更改为使用 .onConflict().ignore() 静默忽略错误,或使用 .onConflict().merge() 使用新数据更新现有行(执行“UPSERT”) .
所以在你的情况下,实现将是:
knex('table')
.insert({
id: id,
name: name
})
.onConflict('id')
.merge()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7008 次 |
| 最近记录: |