【问题标题】:Skip null values on Upsert在 Upsert 上跳过空值
【发布时间】:2017-12-28 11:05:24
【问题描述】:

我正在使用 pg-promise 来处理我的 Postgres 查询,但我无法找到以下查询的解决方案:

我正在尝试创建一种方法来一次批量更新多行, 这是我的代码:

massUpsert: (orgId, entities) => db.tx((t) => {
    const queries = [];
    entities.forEach((entity) => {
      const { id, name, age, type } = entity;
      queries.push(
        t.one(`INSERT INTO public.table (id, name, age, type) 
             VALUES ($1, $2, $3, $4)
              ON CONFLICT (id) DO update
                SET 
                 name = $2,
                 age = $3,
                 type = $4
              RETURNING *`,
        [id, name, age, type]));
    });
    return t.batch(queries);
}),

现在的问题是,在某些情况下,我的一个或多个字段为 null,我希望数据库保留旧值而不是用 null 替换它。

有什么建议吗?

【问题讨论】:

  • 您是否考虑过在数据库本身上使用触发器?
  • 你不应该在ON CONFLICT中使用name = $2之类的东西,它应该是name = excluded.name,你可以通过检查null的函数来进一步改进。
  • @vitaly-t 我没完全理解你,你用excluded.name是什么意思?
  • 这是标准解决方案,excluded 是保留名称,指的是冲突列。检查 PostgreSQL 文档。
  • @vitaly-t,据我所知,排除并不能满足我对冲突列的需求,而不是更新其他列,我唯一想要的防止是在更新时忽略更新具有空值的列。

标签: javascript node.js pg-promise


【解决方案1】:

使用helpers 方法生成查询:

const skipIfNull = name => ({name, skip: c => c.value === null});
    
const cs = new pgp.helpers.ColumnSet([
    '?id',
    skipIfNull('name'),
    skipIfNull('age'),
    skipIfNull('type')
], {table: 'table'});

查看类型 ColumnSetColumn

从样本data生成查询:

const data = {
    id: 1,
    name: null, // will be skipped
    age: 123,
    type: 'tt'
};
    
    const query = pgp.helpers.insert(data, cs) + ' ON CONFLICT(id) DO UPDATE SET ' +
        pgp.helpers.sets(data, cs) + ' RETURNING *';

将生成:

INSERT INTO "table"("id","name","age","type") VALUES(1,null,123,'tt')
ON CONFLICT(id) DO UPDATE SET "age"=123,"type"='tt' RETURNING *

更新:通过assignColumns 的新语法优于sets 方法。

但请注意,根据方法set API,如果您的所有条件列都是null,它将返回一个空字符串,因此生成的查询将无效。您将需要为此添加支票;)

另外,考虑到您正在生成多插入,可以只生成一个多行插入,从而提供更好的性能。为此,请参阅Multi-row insert with pg-promise

另见:

【讨论】:

  • 解决方案有效,感谢您的快速回答。很高兴知道图书馆有一个所有者:)
  • 有没有办法使用 pgp.helpers.insert(data, cs) 来生成一个在插入时跳过 NULL 值的查询?其背后的逻辑是使用表中设置的默认值,因为字段包含 NOT-NULL 约束。
  • 我已经尝试使用上述解决方案,但它仍然会生成一个在缺失字段上插入 null 的查询,请参见此处的示例代码:gist.github.com/RoncoCo/70c07ff57375c83f77b18fbe6f0dab1e
  • @Ronco 您对可选列的定义不符合您尝试执行的逻辑。在那里查看我的答案。
  • 有没有办法对列的组合进行唯一约束?即 - const cs = new pgp.helpers.ColumnSet([ '?(id, external_id)', skipIfNull('name'), skipIfNull('age'), skipIfNull('type') ], {table: 'table' });所以,在这种情况下,唯一的将在 id AND external_id
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-08
  • 2016-07-30
相关资源
最近更新 更多