【问题标题】:update equivalent of WHERE '1' = '1'更新相当于 WHERE '1' = '1'
【发布时间】:2016-06-06 19:45:19
【问题描述】:

当为我的 sql 动态生成 WHERE 子句时,我喜欢将 WHERE '1' = '1' 硬编码到 sql 中,这样我就不必跟踪是否在每个后续子句前面加上 AND。这在很多地方都有很好的记录,例如stackoverflow question

是否有等效的模式为UPDATE 语句动态生成SET 子句?我宁愿不跟踪是否需要在前面加上逗号。如果没有任何通用的解决方案,这将用于通过 jdbc 与 oracle 数据库进行交互。

编辑 对于我的特定用例,我需要动态更改正在设置的列。因此,任何要求查询包含所有正在设置的列的解决方案都是不可行的。我们有一个包含 20 多列的表,但在任何给定时间只有 3 或 4 列会发生变化。我们进行了一些负载测试,发现满足性能目标的唯一方法就是发送需要更新的数据。现在我只是想编写漂亮的代码来做到这一点。

【问题讨论】:

  • 简短回答是否定的。就我个人而言,我讨厌“1=1”的东西,并且更喜欢编写更智能的逻辑,该逻辑知道是根据需要连接多少表达式来预先添加, 还是and。您可能想观察系统必须处理的解析负载 - 确保每次生成 SET 子句时列的顺序相同,以尽量减少这种情况。
  • 这行得通:DECLARE @dummy VARCHAR(1) = 'a'; UPDATE my_table SET @dummy = @dummy WHERE 1 = 1 AND my_second_column = 'My Second Value'。但是,这不是:DECLARE @dummy VARCHAR(1) = 'a'; UPDATE my_table SET my_first_column = 'My First Value', @dummy = @dummy WHERE 1 = 1 AND my_second_column = 'My Second Value'

标签: sql oracle jdbc


【解决方案1】:

为了附加逗号而避免跟踪列数的一种方法是始终分配所有可能的列,并传递一组控制变量来决定是否应分配列:

UPDATE MyTable
SET
    col1 = CASE ? WHEN 1 THEN ? ELSE col1 END
,   col2 = CASE ? WHEN 1 THEN ? ELSE col2 END
,   col3 = CASE ? WHEN 1 THEN ? ELSE col3 END
WHERE
    ... -- condition goes here

奇数索引处的参数是您传递的标志,以指示必须设置相应的列。对应偶数索引处的参数是您要设置的值,如果您没有设置相应的字段,则为NULL

这种方法使您需要传递的 JDBC 参数数量增加了一倍,但作为回报,您会得到一个语句,其中所有列的位置都是固定的,因此您可以准备和重用它,而不是动态构建它。

【讨论】:

  • 如果底层 Oracle 数据库有许多 UPDATE 触发器,这会使事情变得复杂,因为 Oracle 在确定是否应该触发触发器时不会区分 UPDATE mytable SET mycolumn = mycolumn 和 'UPDATE mytable SET mycolumn = mynewvalue` .
  • +1 是一个很好的答案,不幸的是不符合我的用例。我用更多标准更新了原始问题,抱歉不清楚。
  • @Josh "[我们] 发现满足性能目标的唯一方法是只发送需要更新的数据" 您仍然只发送需要更新的数据,其余的列将是NULLs,因此它们只占用很少的带宽。能够准备语句,而不是每次都使用不同的 SQL,应该会为您节省不少时间。
  • 不会传递不变的列仍然会导致数据库花时间“写”下值,即使它是相同的值?例如,如果其中一列是一大块文本怎么办?
  • @Josh 根据this article 的说法,Oracle 针对更新不更改值的情况进行了一些优化。例如,当列被索引时,Oracle 不会触及索引。不过,它会写入撤消和重做日志,但从文章中不清楚这是更新行的所有列发生的事情,还是仅发生在更新中提到的列。找出答案的最好方法当然是分析。
【解决方案2】:

首先,如果没有任何变化,最好不要执行查询。

但如果你必须这样做,或者以其他方式这样做成本更高,你通常可以这样做:

UPDATE 
  MY_TABLE
SET
  <if test="xx">  COL1='VAL1',</if>
  ID=ID
where 1=1
  COL1 like 'VAL%';

ID=ID 充当 noop。

请记住,这仍然会执行带有所有“副作用”的更新,例如运行触发器。

【讨论】:

  • 单行更新永远不会锁定 Postgres 中的整个表。无论 WHERE 条件或更新哪些列
  • @a_horse_with_no_name 感谢您的评论。它发生在 Oracle 上,给我带来了严重的问题,所以我决定更新答案。
  • Oracle 在执行UPDATE 时也永远不会锁定整个表
  • 感谢您的评论,我现在明白我的结论可能过于夸张了。我遇到的情况略有不同。请看asktom.oracle.com/Misc/something-i-recently-unlearned.html
猜你喜欢
  • 2018-05-16
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 2015-07-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
相关资源
最近更新 更多