【问题标题】:Nested CASE statement in UPDATE SET clauseUPDATE SET 子句中的嵌套 CASE 语句
【发布时间】:2017-06-10 21:25:26
【问题描述】:

我正在尝试根据一组条件切换一个值,我注意到在我的 UPDATE 表达式的 SET 子句中有一个嵌套的 CASE 语句时,列没有更新。

当存在简单的 CASE 表达式时,列似乎正在更新。但是,对于本示例中的 OVERRIDDEN_CHECK_NUMBER 和 OVERRIDDEN_AMOUNT,列不会更新。

UPDATE 中的 OVERRIDDEN_DATE、OVERRIDDEN_USER_ID、CHECK_NO 和 AMOUNT 列正在更新,没有问题。

谁能告诉我为什么 OVERRIDDEN_CHECK_NUMBER 和 OVERRIDDEN_AMOUNT 不会在这个 UPDATE 语句中更新?

在 UPDATE 表达式的 SET 子句中是否没有嵌套 CASE 语句?

SQL 示例

UPDATE WAREHOUSE.BANK_STATEMENT_ACTIVITY
    SET OVERRIDDEN_CHECK_NO       = --(CASE :btn                                          
                                        (CASE WHEN (:btn = '1') THEN CASE WHEN '141973' = '141973' THEN NULL
                                                                           WHEN '141973' != '999999' THEN LPAD(TRIM(141973), 12, '0')
                                                                      END
                                        WHEN (:btn = '2') THEN '1740 - Previously Paid Warrant'
                                        ELSE NULL
                                    END),
        OVERRIDDEN_AMOUNT         = --(CASE :btn
                                        (CASE WHEN (:btn = '1') THEN CASE WHEN 253.20 = 253.20 THEN NULL
                                                                           WHEN 253.20 != 999.99 THEN LPAD(TRIM(253.20), 12, '0')
                                                                      END
                                        WHEN (:btn = '2') THEN NULL
                                        ELSE NULL
                                    END),
        OVERRIDDEN_DATE           = SYSDATE,
        OVERRIDDEN_USER_ID        = 1009,
        CHECK_NO                  = (CASE :btn
                                        WHEN '1' THEN LPAD(TRIM(999999), 12, '0')
                                        WHEN '2' THEN '142775'
                                        ELSE NULL
                                        END),
        AMOUNT                    = (CASE :btn
                                        WHEN '1' THEN TRIM(78.60)
                                        WHEN '2' THEN TRIM(253.20)
                                        ELSE NULL
                                        END)
        WHERE TO_NUMBER(CHECK_NO) = (CASE :btn
                                        WHEN '1' THEN '141973'
                                        WHEN '2' THEN '142775'
                                        ELSE NULL
                                    END)
        AND AMOUNT                = (CASE :btn
                                        WHEN '1' THEN 78.60
                                        WHEN '2' THEN 253.20
                                        ELSE NULL
                                    END)
        AND TRUNC(LOAD_DATE)      = (CASE :btn
                                        WHEN '1' THEN TRUNC(LOAD_DATE)
                                        WHEN '2' THEN (SELECT (MAX(LOAD_DATE)) FROM WAREHOUSE.BANK_STATEMENT_ACTIVITY)
                                        ELSE NULL
                                        END)
        AND BANKACCTNO            = (SELECT LONGDESC 
                                     FROM TCMS.COMPLEMENTARY_VALIDATIONS
                                     WHERE TEXTCODE = 'BANKACCT'
                                     AND CODE = 80);

编辑

在修复了@mathguy 通过编辑器指出更新查询的逻辑问题后,它起作用了。但是,当通过 PL/SQL 包执行此操作时,表更新失败。

这是更新前的内容:

Before - result

她是后来的结果:

After - result

它们是相同的。

这是实际的打包过程:

PROCEDURE UpdateBankStatementActivity( btn IN VARCHAR2)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE( 'UpdateBankStatementActivity - btn: ' || btn );
DBMS_OUTPUT.PUT_LINE( 'UpdateBankStatementActivity - bsa_rec.OVERRIDDEN_CHECK_NO: ' || bsa_rec.OVERRIDDEN_CHECK_NO || CHR(10) ||
                                                    'bsa_rec.OVERRIDDEN_AMOUNT: ' || bsa_rec.OVERRIDDEN_AMOUNT || CHR(10) ||
                                                    'bsa_rec.CHECK_NO: ' || bsa_rec.CHECK_NO || CHR(10) ||
                                                    'bsa_rec.AMOUNT: ' || bsa_rec.AMOUNT || CHR(10) ||
                                                    'bsa_rec.LOAD_DATE:' || bsa_rec.LOAD_DATE );
    UPDATE WAREHOUSE.BANK_STATEMENT_ACTIVITY
    SET OVERRIDDEN_CHECK_NO       = --(CASE :btn                                          
                                        (CASE WHEN (btn = '1') THEN CASE WHEN bsa_rec.OVERRIDDEN_CHECK_NO = bsa_rec.CHECK_NO THEN NULL
                                                                         WHEN bsa_rec.OVERRIDDEN_CHECK_NO != bsa_rec.CHECK_NO THEN LPAD(TRIM(bsa_rec.OVERRIDDEN_CHECK_NO), 12, '0')
                                                                    END
                                        WHEN (btn = '2') THEN '1740 - Previously Paid Warrant'
                                        ELSE NULL
                                    END),
        OVERRIDDEN_AMOUNT         = --(CASE :btn
                                        (CASE WHEN (btn = '1') THEN CASE WHEN bsa_rec.OVERRIDDEN_AMOUNT = bsa_rec.AMOUNT THEN NULL
                                                                         WHEN bsa_rec.OVERRIDDEN_AMOUNT != bsa_rec.AMOUNT THEN LPAD(TRIM(bsa_rec.OVERRIDDEN_AMOUNT), 12, '0')
                                                                    END
                                        WHEN (btn = '2') THEN NULL
                                        ELSE NULL
                                    END),
        OVERRIDDEN_DATE           = SYSDATE,
        OVERRIDDEN_USER_ID        = bsa_rec.OVERRIDDEN_USER_ID,
        CHECK_NO                  = (CASE btn
                                        WHEN '1' THEN LPAD(TRIM(bsa_rec.CHECK_NO), 12, '0')
                                        WHEN '2' THEN LPAD(TRIM(bsa_rec.CHECK_NO), 12, '0')
                                        ELSE NULL
                                        END),
        AMOUNT                    = (CASE btn
                                        WHEN '1' THEN TRIM(bsa_rec.OVERRIDDEN_AMOUNT)
                                        WHEN '2' THEN TRIM(bsa_rec.AMOUNT)
                                        ELSE NULL
                                        END)
        WHERE TO_NUMBER(CHECK_NO) = (CASE btn
                                        WHEN '1' THEN bsa_rec.OVERRIDDEN_CHECK_NO
                                        WHEN '2' THEN bsa_rec.CHECK_NO
                                        ELSE NULL
                                    END)
        AND AMOUNT                = (CASE btn
                                        WHEN '1' THEN bsa_rec.OVERRIDDEN_AMOUNT
                                        WHEN '2' THEN bsa_rec.AMOUNT
                                        ELSE NULL
                                    END)
        AND TRUNC(LOAD_DATE)      = (CASE btn
                                     WHEN '1' THEN  TRUNC(bsa_rec.LOAD_DATE)
                                     WHEN '2' THEN (SELECT MAX(LOAD_DATE) FROM WAREHOUSE.BANK_STATEMENT_ACTIVITY)
                                     ELSE NULL
                                     END)
        AND BANKACCTNO            = (SELECT LONGDESC 
                                     FROM TCMS.COMPLEMENTARY_VALIDATIONS
                                     WHERE TEXTCODE = 'BANKACCT'
                                     AND CODE = 80);

    COMMIT;
END UpdateBankStatementActivity;

第一个SQL CODE sn -p中的参数值与PL/SQL块中的参数一致。

【问题讨论】:

  • 我相信这应该可行。您能否发布一个示例,其中包含更新前的数据、更新运行(包括变量值)和更新后的数据。我相信一个不工作的专栏就足以解释这个问题。
  • mathguy 指出了我纠正的逻辑中的一个错误,并且通过编辑器进行了更新。但是,通过包执行时,表格没有更新……我会尽快提供示例。
  • @TheSchnitz - 确保更改包中过程中的代码,然后重新编译所有内容。否则 Oracle 仍将使用“最后已知的良好”版本!
  • 谢谢@mathguy。每次通过包执行时,我都在重新编译和查看表数据。
  • 我已经添加了请求的信息和一些附加信息。感谢您的帮助!

标签: sql oracle sql-update case


【解决方案1】:

“不更新”是什么意思?

:btn = '1' 时,嵌套的case 表达式中存在明显的逻辑缺陷。即,“内部”case 表达式的第一个分支始终计算为 TRUE,因此每次传入 :btn = '1' 时,“更新值”将为 null。这是你注意到的问题吗?然后:对于overridden_amount,结果将始终为null,因此;对于overridden_check_no,它不会是null 当且仅当:btn = '2'

请注意,您可以使用与简单表达式相同的语法编写“外部”case 表达式:case :btn when '1' then case .... end else ... end

编辑:回答您修改后的问题(也许)。我不确定我能否完全遵循逻辑;但是示例中发生了什么(假设您使用btn = '1' 调用该过程是这样的:

overridden_check_nooverridden_amount 在原始表中都是 null。在两列的嵌套(内部)case 表达式中,您检查两列,=!=。当其中一个术语是null 时,两个测试都不是 true!因此,case 评估属于else 子句,或者当不包括else 时,默认为nullupdate 确实有效,它只是将值更新为null,因为内部case 语句中的任何“实际分支”都没有评估为true

不过,您说,如果您直接从您的编辑器将它作为独立的 SQL update 运行,那么它就可以正常工作。我想知道这怎么可能,除非 - 再一次 - 过程中的代码与您在编辑器中的代码不同。

【讨论】:

  • 感谢您指出这一点。话虽如此,当我在编辑器中单独测试它时,它似乎更新了表,但是当我通过我的 PL/SQL 包执行它时,表没有更新。
  • 我觉得很尴尬。我刚刚发现我的错误。在我的测试过程中,我传入的数量不正确,这基本上使 WHERE 子句对于更新特定测试记录不正确。非常感谢你的帮助!道歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 2016-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多