将同一变量传递到 SQL 语句的多个部分时出错

Posted

技术标签:

【中文标题】将同一变量传递到 SQL 语句的多个部分时出错【英文标题】:Error with passing in the same variable into multiple parts of SQL statement 【发布时间】:2022-01-09 12:45:33 【问题描述】:

所以我有一个 Node.js 查询,它应该传入这三个值,并为具有特定 id 的用户按特定数量更新特定列:

await client.query(sqlStatement, [columnName, changeBy, id])

“sqlStatement”看起来像:

'UPDATE tableName SET ($1) = ($1) + ($2) WHERE id = ($3)'

如您所见,它应该传入 SQL 语句如下所示的值:

'UPDATE tableName SET columnName = columnName + changeBy WHERE id = id'

我也尝试将 sqlStatement 编写如下(并且只需将 columnName 两次传递到查询中,但这也会导致错误:

'UPDATE tableName SET ($1) = ($2) + ($3) WHERE id = ($4)'

返回的错误是error: syntax error at or near "$1"。

不知道如何解决这个问题——非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

发生这种情况的原因是node-postgres doesn't support query parameters for identifiers 和SET 之后的列名是一个标识符。此外,即使这有效,除非 node-postgres 以某种方式将整个 ($1)(带括号)替换为您的值,否则您会得到

ERROR: source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression.

如果你想保留node-postgres,它的documentation建议在这种情况下使用pg-format来构建动态SQL语句。如果您考虑替代方案,您可以查看Knex.js,它将为您构建查询,如下所示:

knex('tableName')
   .update( 
       columnName: knex.raw('?? + ?',['columnName',changeBy])
   )
   .where('id', id)

同时,作为一种解决方法,您应该能够自行将 sqlStatement 设置为动态 SQL 查询:

do language plpgsql $$ begin execute format('UPDATE test SET %I = %I + %s WHERE id = %s','$1','$1',$2,$3); end$$;

然后尝试一下。请注意,我从更新列周围删除了括号以避免多列更新错误。应该发生的是node-postgres 将上述评估为

do language plpgsql $$ begin execute format('UPDATE test SET %I = %I + %s WHERE id = %s','col','col',51,72); end$$;

并将其传递给 PostgreSQL,它应该将其执行为

UPDATE test SET "col" = "col" + 51 WHERE id = 72;

来自doc:

%I 用于I标识符,如果需要,PostgreSQL 会自动引用。 %L 用于字符串 Literals %s 用于s简单的s字符串替换,在某种意义上它不会被引用,所以它可以用于数字文字

【讨论】:

以上是关于将同一变量传递到 SQL 语句的多个部分时出错的主要内容,如果未能解决你的问题,请参考以下文章

JS实践遇到问题,多个变量多个页面如何避免出错

将多个变量传递到 url 中的另一个页面

将变量传递给炮兵脚本时出错

如何将多个变量传递给 Angular 2 中的组件?

在 PL/SQL 存储过程中将多个变量传递给 WHERE 条件

PL/SQL:, 如何将变量传递给 SELECT 语句并返回所有结果行