Oracle查询中Case语句传递日期绑定变量报错的解决方案咨询
当然可以在Oracle的CASE语句里使用绑定变量啦!你碰到的ORA-00932错误主要有两个核心原因:一是会话的NLS_DATE_LANGUAGE设置可能导致to_char(:sysdate2, 'Dy')返回的不是英文的'Mon'(比如中文环境会返回'星期一'),让CASE分支匹配失败;二是你用了两个不同的绑定变量:sysdate1和:sysdate2,如果传递的值不一致或者类型不正确,就会触发类型不匹配问题。
下面给你两个可靠的替代方案,完美满足你的需求:
方案1:用ISO周判断周一(不受语言设置影响)
这个方法通过ISO周规则判断日期是否为周一,完全不依赖会话的语言配置,同时只用一个绑定变量避免传递错误:
select * from ( SELECT S."TRADEDATE",S."ACCOUNT_NAME",S."BOOKING_AMOUNT",S."ACCOUNT_NUMBER",(CASE WHEN BOOKING_AMOUNT <0 THEN S."CREDIT" ELSE S."DEBIT" END) AS "DEBIT" , (CASE WHEN BOOKING_AMOUNT <0 THEN S."DEBIT" ELSE S."CREDIT" END) AS "CREDIT", U.VALUE_DT , U.AC_NO , NVL(U.BOOKED_AMOUNT ,0) BOOKED_AMOUNT FROM SXB S FULL OUTER JOIN UBS U ON S.ACCOUNT_NUMBER = U.AC_NO AND S.TRADEDATE = U.VALUE_DT UNION ALL SELECT BOOKING_DATE TRADEDATE, 'SAXO RECON' ACCOUNT_NAME, SUM((Case when DR_CR_INDICATOR = 'D' then AMOUNT*-1 when DR_CR_INDICATOR = 'C' then AMOUNT end)) BOOKING_AMOUNT, EXTERNAL_ACCOUNT ACCOUNT_NUMBER, 'Matched - ' ||A.MATCH_INDICATOR AS DEBIT, NULL AS CREDIT, VALUE_DATE VALUE_DT, NULL AS AC_NO, 0 AS BOOKED_AMOUNT FROM FCUBS.RETB_EXTERNAL_ENTRY A WHERE A.EXTERNAL_ENTITY = 'SAXODKKKXXX' AND A.EXTERNAL_ACCOUNT = '78600/COMMEUR' group by BOOKING_DATE , EXTERNAL_ACCOUNT , VALUE_DATE, MATCH_INDICATOR order by tradedate, account_name) where tradedate = trunc( :input_date - CASE WHEN TRUNC(:input_date) = TRUNC(:input_date, 'IW') THEN 3 -- 周一,减3天到上周五 ELSE 1 -- 其他工作日,减1天到前一个工作日 END );
原理说明:TRUNC(:input_date, 'IW')会返回当前日期所在ISO周的周一(ISO周默认以周一为第一天),如果原日期的截断值等于这个值,就说明是周一,判断逻辑稳定可靠。
方案2:强制指定语言匹配'Mon'
如果你还是想用to_char的方式判断星期,只需要在函数中强制指定英文语言,确保返回结果是'Mon':
select * from ( SELECT S."TRADEDATE",S."ACCOUNT_NAME",S."BOOKING_AMOUNT",S."ACCOUNT_NUMBER",(CASE WHEN BOOKING_AMOUNT <0 THEN S."CREDIT" ELSE S."DEBIT" END) AS "DEBIT" , (CASE WHEN BOOKING_AMOUNT <0 THEN S."DEBIT" ELSE S."CREDIT" END) AS "CREDIT", U.VALUE_DT , U.AC_NO , NVL(U.BOOKED_AMOUNT ,0) BOOKED_AMOUNT FROM SXB S FULL OUTER JOIN UBS U ON S.ACCOUNT_NUMBER = U.AC_NO AND S.TRADEDATE = U.VALUE_DT UNION ALL SELECT BOOKING_DATE TRADEDATE, 'SAXO RECON' ACCOUNT_NAME, SUM((Case when DR_CR_INDICATOR = 'D' then AMOUNT*-1 when DR_CR_INDICATOR = 'C' then AMOUNT end)) BOOKING_AMOUNT, EXTERNAL_ACCOUNT ACCOUNT_NUMBER, 'Matched - ' ||A.MATCH_INDICATOR AS DEBIT, NULL AS CREDIT, VALUE_DATE VALUE_DT, NULL AS AC_NO, 0 AS BOOKED_AMOUNT FROM FCUBS.RETB_EXTERNAL_ENTRY A WHERE A.EXTERNAL_ENTITY = 'SAXODKKKXXX' AND A.EXTERNAL_ACCOUNT = '78600/COMMEUR' group by BOOKING_DATE , EXTERNAL_ACCOUNT , VALUE_DATE, MATCH_INDICATOR order by tradedate, account_name) where tradedate = trunc( :input_date - CASE WHEN to_char(:input_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') = 'Mon' THEN 3 ELSE 1 END );
原理说明:在to_char函数中添加第三个参数'NLS_DATE_LANGUAGE=ENGLISH',强制返回英文的星期缩写,彻底解决不同语言环境下的匹配问题。
额外提醒
一定要确保传递给:input_date的是DATE类型的绑定变量,不要传字符串或数字,否则还是会触发类型不匹配的错误。如果之后需要处理节假日的情况,这个逻辑可以再扩展,但当前只跳过周末的需求,上面的方案完全够用。
内容的提问来源于stack exchange,提问作者nilesh chopadkar
相关产品推荐
相关产品推荐

