如何使用 knex 使用 "Insert ... ON DUPLICATE KEY UPDATE" 添加多行
How to add multiple rows using "Insert ... ON DUPLICATE KEY UPDATE" using knex
所以我最近一直在玩 knex,但是我发现自己处于一种不知道该做什么的情况下。
所以我有这个查询:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
[
['val1', 'hello', 'world'],
['val2', 'ohayo', 'minasan'],
]);
由于某些原因,它抛出一个错误 Expected 2 bindings, saw 3
。
我试过:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
['val1', 'hello', 'world'],
['val2', 'ohayo', 'minasan'],
);
这次没有报错,只是插入了第一个数组。
我还尝试将值设为对象:
[
{col1: 'val1', col2: 'hello', col3: 'world'},
{col1: 'val2', col2: 'ohayo', col3: 'minasan'},
]
但还是没有运气。
如果您一次只需要插入固定数量的行,您可以试试这个:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
['val1', 'hello', 'world', 'val2', 'ohayo', 'minasan'],
);
如果您不知道一次需要插入多少个,可以编写一个脚本,根据需要多次添加 (?, ?, ?),
。
var questionMarks = "";
var values = [];
var rows = [
{col1: 'val1', col2: 'hello', col3: 'world'},
{col1: 'val2', col2: 'ohayo', col3: 'minasan'},
];
rows.forEach(function(value, index){
questionMarks += "("
Object.keys(value).forEach(function(x){
questionMarks += "?, ";
values.push(value[x]);
});
questionMarks = questionMarks.substr(0, questionMarks.length - 2);
questionMarks += "), ";
});
questionMarks = questionMarks.substr(0, questionMarks.length - 2); //cut off last unneeded comma and space
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES " + questionMarks + " ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)", values);
我将此代码写入 insert/update 单行作为对象或多行作为对象数组:
function insertOrUpdate(knex: Knex, tableName: string, data: any) {
const firstData = data[0] ? data[0] : data;
return knex.raw(knex(tableName).insert(data).toQuery() + " ON DUPLICATE KEY UPDATE " +
Object.getOwnPropertyNames(firstData).map((field) => `${field}=VALUES(${field})`).join(", "));
}
如果您使用的是 PostgreSQL,Nathan 的解决方案将不起作用,因为没有 ON DUPLICATE KEY UPDATE
。所以在 PostgreSQL 中你应该使用 ON CONFLICT ("id") DO UPDATE SET
:
const insertOrUpdate = (knex, tableName, data) => {
const firstData = data[0] ? data[0] : data;
return knex().raw(
knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
);
};
如果您正在使用 Objection.js
(knex 的包装器),那么(在这种情况下不要忘记导入 knex):
const insertOrUpdate = (model, tableName, data) => {
const firstData = data[0] ? data[0] : data;
return model.knex().raw(
knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
);
};
所以我最近一直在玩 knex,但是我发现自己处于一种不知道该做什么的情况下。
所以我有这个查询:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
[
['val1', 'hello', 'world'],
['val2', 'ohayo', 'minasan'],
]);
由于某些原因,它抛出一个错误 Expected 2 bindings, saw 3
。
我试过:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
['val1', 'hello', 'world'],
['val2', 'ohayo', 'minasan'],
);
这次没有报错,只是插入了第一个数组。
我还尝试将值设为对象:
[
{col1: 'val1', col2: 'hello', col3: 'world'},
{col1: 'val2', col2: 'ohayo', col3: 'minasan'},
]
但还是没有运气。
如果您一次只需要插入固定数量的行,您可以试试这个:
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)",
['val1', 'hello', 'world', 'val2', 'ohayo', 'minasan'],
);
如果您不知道一次需要插入多少个,可以编写一个脚本,根据需要多次添加 (?, ?, ?),
。
var questionMarks = "";
var values = [];
var rows = [
{col1: 'val1', col2: 'hello', col3: 'world'},
{col1: 'val2', col2: 'ohayo', col3: 'minasan'},
];
rows.forEach(function(value, index){
questionMarks += "("
Object.keys(value).forEach(function(x){
questionMarks += "?, ";
values.push(value[x]);
});
questionMarks = questionMarks.substr(0, questionMarks.length - 2);
questionMarks += "), ";
});
questionMarks = questionMarks.substr(0, questionMarks.length - 2); //cut off last unneeded comma and space
knex.raw("INSERT INTO tablename (`col1`, `col2`, `col3`) VALUES " + questionMarks + " ON DUPLICATE KEY UPDATE col2 = VALUES(`col2`)", values);
我将此代码写入 insert/update 单行作为对象或多行作为对象数组:
function insertOrUpdate(knex: Knex, tableName: string, data: any) {
const firstData = data[0] ? data[0] : data;
return knex.raw(knex(tableName).insert(data).toQuery() + " ON DUPLICATE KEY UPDATE " +
Object.getOwnPropertyNames(firstData).map((field) => `${field}=VALUES(${field})`).join(", "));
}
如果您使用的是 PostgreSQL,Nathan 的解决方案将不起作用,因为没有 ON DUPLICATE KEY UPDATE
。所以在 PostgreSQL 中你应该使用 ON CONFLICT ("id") DO UPDATE SET
:
const insertOrUpdate = (knex, tableName, data) => {
const firstData = data[0] ? data[0] : data;
return knex().raw(
knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
);
};
如果您正在使用 Objection.js
(knex 的包装器),那么(在这种情况下不要忘记导入 knex):
const insertOrUpdate = (model, tableName, data) => {
const firstData = data[0] ? data[0] : data;
return model.knex().raw(
knex(tableName).insert(data).toQuery() + ' ON CONFLICT ("id") DO UPDATE SET ' +
Object.keys(firstData).map((field) => `${field}=EXCLUDED.${field}`).join(', ')
);
};