问题描述
我知道我的sql知识很薄弱。不幸的是,我发现自己所知道的比我以前所想的要少。
我写了一个UPDATE
命令,可以在使用表单的简单HTML设置页面中使用。 (在表单数据到达UPDATE sql之前,对表单数据进行了一些浏览器端验证和服务器端验证。)
我的目标是更新2行中的1列。没有其他的。但是我错了。它使用期望的值更新了两个目标行。 sql还NULL
列了所有其他行中所有值的列。
我的问题1:是什么导致了我的sql? 我的问题2:是否有更好的方法来执行此更新?
<cfquery datasource="OurDBLocation" name="changeValues">
UPDATE soMetable
SET rowvalueB = CASE
WHEN rowvalueA = 'A123' THEN #val(FORM.a123value)#
WHEN rowvalueB = 'A456' THEN #val(FORM.a456value)#
END
OUTPUT INSERTED.*
WHERE rowvalueA IN ('A123','A456')
</cfquery>
注意:这是一种内部形式,只有具有VPN访问我们代码库权限的开发人员才能访问。对于不了解#val(FORM.a123value)#
解决方法
编辑:2020-10-07
对于最新注释,如果要减少UPDATE
的数量,尤其是当它不更改值但仍导致写入时,可以使用CTE仅过滤需要更新的行然后与那些人一起工作。
<cfquery datasource="OurDBLocation" name="changeValues">
; WITH cte AS (
SELECT rowvalueB
FROM sometable
WHERE rowvalueA = 'A123'
OR ( rowvalueA = 'A456' AND rowvalueB = 'A456' )
)
UPDATE cte
SET rowvalueB =
CASE
WHEN rowvalueA = 'A123' THEN <cfqueryparam value="#val(FORM.a123value)#" cfsqltype="cf_sql_integer">
ELSE <cfqueryparam value="#val(FORM.a456value)#" cfsqltype="cf_sql_integer">
END
OUTPUT INSERTED.*
;
</cfquery>
CTE UPDATE非常棒,如果可以按照您的SQL风格使用它们(并且通过标记tsql
,我猜您是SQL Server)。测试它以确保它适合您的情况。我不知道为什么cfquery
无法正确运行CTE UPDATE,但是我现在无法对其进行测试。
解释正在发生的事情:
;WITH cte AS..
创建命名的CTE数据集。另请参见https://www.sqlshack.com/sql-server-common-table-expressions-cte/
SELECT...
定义构成CTE的数据。由于您要过滤rowvalueA IN (A123,A456)
,然后更新不同的值,因此我简化了WHERE
语句。当FORM.a456
和rowvalueB
都等于'A456'时,您只会更新rowvalueA
值。因此,CTE会过滤掉rowvalueA=A456
但rowvalueB
是A456
以外的所有行。这些将是最初重置为NULL
的记录。
然后,使用普通的UPDATE
语句更新CTE,这将通过管道传输到表中的实际行。由于您仍在更新中使用条件值,因此我们必须使用CASE...WHEN...
,但行已被过滤和简化。我们只需要检查rowvalueA=A123
。
还要注意,当我提到客户端验证时,我并不是说不这样做。我只是指出,绕过客户端验证很简单,因此不应依赖于任何形式的验证,这些验证除了用于客户端显示或易于使用之外,还用于其他任何用途。
==========原始答案=====================
如果我正确理解您的意图,则您的查询似乎大部分是正确的。您只更新表中的rowdataB
。但是,如果不满足您的WHEN
条件,则不会提供默认值,因此将NULL
分配给它。
<cfquery datasource="OurDBLocation" name="changeValues">
UPDATE sometable
SET rowvalueB =
CASE
WHEN rowvalueA = 'A123' THEN <cfqueryparam value="#val(FORM.a123value)#" cfsqltype="cf_sql_integer">
WHEN rowvalueB = 'A456' THEN <cfqueryparam value="#val(FORM.a456value)#" cfsqltype="cf_sql_integer">
ELSE rowvalueB
END
OUTPUT INSERTED.*
WHERE rowvalueA IN ('A123','A456')
</cfquery>
如果您的rowvalueB
中的WHEN
条件都不满足,这只会将CASE
的值重新分配给它自己。由于存在WHERE
子句,它将忽略任何其他行。
我认为如果OUTPUT INSERTED.*
是rowvalueA
,这可能会将行添加到您的'A456'
,因为它将在您的WHERE
子句中匹配,但是不在您的WHEN
子句中。如果您不打算这样做,则可能要更改WHERE
。