SQL 更新案例

SQL UPDATE WHERE CASE

我知道我的 SQL 知识薄弱。不幸的是,我发现我知道的比我以前想象的要少。

我写了一个 UPDATE 命令,用于使用表单的简单 HTML 设置页面。 (在数据到达更新 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)#

的人,我们在后端使用 Lucee(又名 ColdFusion)

编辑: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 更新非常棒,如果它们符合您的 SQL 风格(通过标记 tsql,我猜您是 SQL 服务器)。测试它以确保它适用于您的情况。我不知道为什么 cfquery 不能 运行 CTE 更新正确,但我现在无法测试它。

解释正在发生的事情: ;WITH cte AS.. 创建命名的 CTE 数据集。另见 https://www.sqlshack.com/sql-server-common-table-expressions-cte/ SELECT... 定义构成 CTE 的数据。由于您想过滤 rowvalueA IN (A123,A456) 但随后更新不同的值,我简化了 WHERE 语句。当 rowvalueBrowvalueA = 'A456' 时,您只会更新 FORM.a456 值。因此,CTE 过滤掉所有 rowvalueA=A456rowvalueB 不是 A456 的行。这些将是最初重置为 NULL 的记录。 然后,您使用普通的 UPDATE 语句来更新 CTE,这将通过管道传输到 table 中的实际行。由于您仍在更新中使用条件值,因此我们必须使用 CASE...WHEN... 但行已被过滤和简化。我们只需要检查是否 rowvalueA=A123.

另请注意,当我提到客户端验证时,我并不是说不要这样做。我只是指出 client-side 验证很容易绕过,因此不应依赖任何类型的验证,而这些验证的目的不仅仅是为了客户端显示或易用性。

========== 原始答案 =======================

如果我正确理解了您的意图,那么您的查询似乎大部分是正确的。您只在 table 中更新 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>

如果满足 CASE 中的 WHEN 条件,这只会将 rowvalueB 的值重新分配回自身。由于 WHERE 子句,它将忽略任何其他行。

认为 如果 rowvalueA'A456',这可能会将行添加到您的 OUTPUT INSERTED.*,因为它将匹配您的 WHERE 子句,但不在 WHEN 子句中。如果这不是您想要的,您可能需要更改 WHERE.