如何使用 knex 使用“Insert ... ON DUPLICATE KEY UPDATE”添加多行

Posted

技术标签:

【中文标题】如何使用 knex 使用“Insert ... ON DUPLICATE KEY UPDATE”添加多行【英文标题】:How to add multiple rows using "Insert ... ON DUPLICATE KEY UPDATE" using knex 【发布时间】:2017-12-09 08:16:27 【问题描述】:

所以我最近一直在玩 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',
]

但仍然没有运气。

【问题讨论】:

查看这篇文章***.com/questions/40543668/batch-update-in-knex他们会告诉你怎么做。 是的,我已经检查过了,事实上我评论了关于“记录”的数据结构的答案,因为不太清楚它是什么样的。 【参考方案1】:

我编写了这段代码来插入/更新单行作为对象或多行作为对象数组:

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(", "));

【讨论】:

【参考方案2】:

如果您一次只需要插入一个固定数字行,您可以试试这个:

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

【讨论】:

我包含一个脚本来计算需要多少(?, ?, ?), 太棒了!有效!谢谢!我将只使用循环来添加 (?, ?, ?) 和数组推送值,因为我不知道要插入的确切行数。 @IamL 如果您遇到困难,请查看添加内容。【参考方案3】:

如果您使用的是 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 使用“Insert ... ON DUPLICATE KEY UPDATE”添加多行的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Knex 上使用 EXISTS 进行子查询?

如何在 RDS 上正确使用 Knex / Bookshelf 和 MySQL

如何使用 knex 使用“Insert ... ON DUPLICATE KEY UPDATE”添加多行

如何在 TypeScript 中使用 Jest 和 Knex 进行测试?

如何在 Knex JS 中使用 IS NOT NULL

使用 Knex,如何将连接表的相关行作为嵌套对象给出?