仅包含具有更新值的列的动态更新语句
Posted
技术标签:
【中文标题】仅包含具有更新值的列的动态更新语句【英文标题】:Dynamic Update Statement with only the columns that have updated values 【发布时间】:2021-11-23 03:27:17 【问题描述】:我需要执行更新语句,并且在发送 http 补丁请求之前我不确定要更新的列。我需要修改员工记录,并且需要构造一个仅包含已更新值的列的更新语句。
该表有列employeerecords(ID,name,dateOfBirth,startyear,endyear,company)。 以及以下示例响应:
"name":"Jim"
更新:发送补丁请求时,我通过 URI 参数提供 ID。我也在Mule 4中实现。我不知道如何完成以下。
更新员工记录 SET -未知- WHERE ID =:ID;
【问题讨论】:
一般来说,应用程序应该始终向后端提供所有的字段值——完整的记录——而不仅仅是更改的值。在您的示例中,数据甚至不包括记录的关键字段:您怎么会知道要更新的 哪个 记录,更不用说要设置什么值了...这不是好的设计。 @pmdba,我在上面提供了更多信息。我通过 URI 参数提供 PK。 这仍然不是一个好的设计。 API 应接受所有参数 - 完整记录 - 作为输入并发出单个预先确定的更新语句。或者,不同的 API 调用可以接受特定的字段子集作为输入,但 SQL 仍然应该是静态的,而不是动态的。为 DML 命令构建动态 SQL 是 SQL 注入或其他问题的秘诀。 我在这里同意@pmdba。从技术上讲,您可以在收到请求后测试每一列,然后从那里构建一个动态 sql,其中包含您要更新的列。 【参考方案1】:您实际上并不需要使用动态 SQL 来解决此问题。假设您使用的是支持 JSON_TABLE
的 Oracle 版本,则以下查询就足够了:
UPDATE employee e
SET (name, dateofbirth, startyear, endyear, company) =
(SELECT NVL(j.name, e.name), NVL(j.dateofBirth, e.dateofBirth),
NVL(j.startyear, e.startyear), NVL(j.endyear, e.endyear),
NVL(j.company, e.company)
FROM JSON_TABLE('"name":"Jim"' --REPLACE WITH ACTUAL REQUEST
COLUMNS(name, dateOfBirth DATE, startyear, endyear, company)) j)
WHERE e.id = 1; --REPLACE WITH ACTUAL ID
我最好将绑定变量用作过程的一部分,而不是对 JSON 和 ID 进行硬编码。
我创建了一个 DBFiddle 来显示查询的有效性:(Link)
编辑 1:添加 NULL
CHECKING
正如 cmets 中所指出的,如果用户将 NULL
传递给请求中的值,我的原始查询将不起作用。我已修改我的查询以使用EXISTS
功能:
UPDATE employee e
SET (name, dateofbirth, startyear, endyear, company) =
(SELECT DECODE(j.name_chk, 1, j.name, e.name),
DECODE(j.dob_chk, 1, j.dateofbirth, e.dateofBirth),
DECODE(j.start_chk, 1, j.startyear, e.startyear),
DECODE(j.end_chk, 1, j.endyear, e.endyear),
DECODE(j.co_chk, 1, j.company, e.company)
FROM JSON_TABLE('"name":"Jim","endyear":null'
COLUMNS(name, name_chk NUMBER EXISTS PATH '$.name',
dateOfBirth DATE, dob_chk NUMBER EXISTS PATH '$.dateofbirth',
startyear, start_chk NUMBER EXISTS PATH '$.startyear',
endyear, end_chk NUMBER EXISTS PATH '$.endyear',
company, co_chk NUMBER EXISTS PATH '$.company')) j)
WHERE e.id = 1;
我也更新了 DBFiddle (Link)
【讨论】:
如果调用 API 的用户想要将其中一列设置为空值,则此方法将不起作用。例如,请求为"name":"Jim","endyear":null
的主体不会将endyear
列设置为空,它会保留旧值。
@EJEgyed 感谢您的评论。你完全正确。我添加了一些功能来检查明确的NULL
。以上是关于仅包含具有更新值的列的动态更新语句的主要内容,如果未能解决你的问题,请参考以下文章