如果为列提供的值不为null,则可选的列更新

时间:2018-12-21 17:07:51

标签: sql postgresql sql-update pg-promise

我有下表:

CREATE TABLE IF NOT EXISTS categories
(
    id SERIAL PRIMARY KEY,
    title CHARACTER VARYING(100) NOT NULL,
    description CHARACTER VARYING(200) NULL,
    category_type CHARACTER VARYING(100) NOT NULL
);

我正在使用pg-promise,并且想提供可选的列更新:

categories.update = function (categoryTitle, toUpdateCategory) {
  return this.db.oneOrNone(sql.update, [
          categoryTitle,
          toUpdateCategory.title, toUpdateCategory.category_type, toUpdateCategory.description,
        ])
}
  • categoryName-是必需的
  • toUpdateCategory.title-是必需的
  • toUpdateCategory.category_type-是可选的(可以传递或未定义)
  • toUpdateCategory.description-是可选的(可以传递或未定义)

我想构建UPDATE查询以仅更新提供的列:

UPDATE categories
SET title=$2,
// ... SET category_type=$3 if $3 is no NULL otherwise keep old category_type value
// ... SET description=$4 if $4 is no NULL otherwise keep old description value
WHERE title = $1
RETURNING *;

如何在Postgres中实现此可选列更新?

2 个答案:

答案 0 :(得分:1)

您可以在新旧值之间coalesce

UPDATE categories
SET title=$2,
    category_type = COALESCE($3, category_type),
    description = COALESCE($4, description) -- etc...
WHERE title = $1

答案 1 :(得分:1)

helpers语法最适合任何pg-promise的动态逻辑:

/* logic for skipping columns: */
const skip = c => c.value === null || c.value === undefined;

/* reusable/static ColumnSet object: */
const cs = new pgp.helpers.ColumnSet(
    [
        'title',
        {name: 'category_type', skip},
        {name: 'description', skip}
    ],
    {table: 'categories'});

categories.update = function(title, category) {
   const condition = pgp.as.format(' WHERE title = $1', title);
   const update = () => pgp.helpers.update(category, cs) + condition;
   return this.db.none(update);
}

如果未指定可选的列属性甚至没有在对象上存在,则可以将跳过逻辑简化为此逻辑(请参见Column逻辑):

const skip = c => !c.exists;

使用的API:ColumnSethelpers.update

另请参阅类似的问题:Skip update columns with pg-promise