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

polhcujo  于 2022-12-03  发布在  Mysql
关注(0)|答案(5)|浏览(199)

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

但还是没有运气。

sgtfey8w

sgtfey8w1#

我编写了以下代码,以插入/更新作为对象的单行或作为对象数组的多行:

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

chy5wohz2#

如果一次只需要插入固定数量的行,可以尝试以下操作:

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

hwamh0ep3#

如果你使用的是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的 Package 器),那么(在这种情况下,不要忘记导入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(', ')
  );
};
sy5wg1nm

sy5wg1nm4#

const db = knex({/* config */});

const records = [
  { id: "1", col1: "hello", col2: "world"],
  { id: "2", col1: "ohayo", col2: "minasan"]
];

const { sql, bindings } = db.table("table").insert(records).toSQL();

// MySQL
// --------------
await db.raw(
  ` ${sql} ON DUPLICATE KEY UPDATE
    col1 = VALUES(col1),
    col2 = VALUES(col2)`,
  bindings
);

// PostgreSQL
// --------------
await db.raw(
  ` ${sql} ON CONFLICT ("id") DO UPDATE
    SET col1 = EXCLUDED.col1,
        col2 = EXCLUDED.col2`,
  bindings
);
1hdlvixo

1hdlvixo5#

2022更新

我现在使用onConflict来实现这个功能,它适用于PostgreSQL、MySQL和SQLite数据库
假设我有一个表,表名为keyvalue,表中包含主键或唯一键

使用方法:

await knex('workspaces_settings')
  .insert({
    key,
    value,
    created_at: new Date(),
    updated_at: new Date(),
  })
  .onConflict(['key', 'value'])
  .merge();

如果键值组合存在,它将简单地根据insert函数中的字段更新值。

对于多个值

您只需在insert中传递一个数组即可:

await knex('workspaces_settings')
  .insert([
    {
      key: '1',
      value: '1',
      created_at: new Date(),
      updated_at: new Date(),
    },
    {
      key: '2',
      value: '2',
      created_at: new Date(),
      updated_at: new Date(),
    },
  ])
  .onConflict(['key', 'value'])
  .merge();

相关问题