创建触发器时出现 PLS-00049: 错误的赋值变量 ':NEW.modify_man'

本文介绍了一个关于Oracle数据库触发器的常见错误案例,即在尝试插入、更新或删除操作时触发器因表结构不匹配而报错。文章详细解释了错误产生的原因,并给出了具体的解决步骤,包括检查表结构和确保字段名正确。
部署运行你感兴趣的模型镜像
create or replace trigger t_hang_info
before insert or update or delete on hang_info
for each row
declare
    pbCount number;
begin
    select count(LANDID) into pbCount from TRADECENTER_LANDHANG where LANDID = :new.land_no;
    if inserting or updating then
        if pbCount<=0 then 
            insert into TRADECENTER_LANDHANG (
            INFORID,
            LANDID,
            LANDNAME,
            STARTTIME,
            ENDTIME,
            HIGHESTPRICE,
            INCPRICE,
            modify_man
            ) values (
            :new.hang_no,
            :new.land_no,
            :new.land_name,
            :new.hang_start_date,
            :new.hang_end_date,            
            :new.hang_start_price,
            :new.hang_inc_price,
            :new.modify_man            
            );
        else
            update TRADECENTER_LANDHANG set 
            INFORID = :new.hang_no,
            LANDID = :new.land_no,
            LANDNAME = :new.land_name,
            STARTTIME = :new.hang_start_date,
            ENDTIME = :new.hang_end_date,
            --HIGHESTPRICE = :new.hang_start_price,
            INCPRICE = :new.hang_inc_price
            where landid = :new.land_no;
        end if;
    end if;
    if deleting then 
      delete from TRADECENTER_LANDHANG where landid = :old.land_no;
    end if;
end;
两个带颜色的地方报错
PLS-00049: 错误的赋值变量 ':new.modify_man'
PLS-00049: 错误的赋值变量 ':new.modify_man'
检查表结构后发现是表中没有modify_man字段,所以造成这样的错误,加上之后就测试通过了。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think> 我们之前已经修复了OPERTIME字段(显式转换为字符串),但错误依然发生在第70行(新代码中的位置)和第22行(旧代码位置)。 考虑到错误信息指向日期格式问题,我们需要重新检查所有涉及日期/间字段的处理。 表结构回顾: 1. financial_cloud_xcff 表中: - DJRQ: VARCHAR2(10) [非空] -> 我们使用 TO_CHAR(SYSDATE, 'YYYY-MM-DD') 赋值 -> 格式为10位,符合。 - OPERTIME: VARCHAR2(50) [可为空] -> 已修复为 TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') -> 长度19,小于50。 2. HR_REMOTE_PROCESS 表中: - START_TIME: TIMESTAMP [可为空] -> 我们插入NULL。 然而,错误再次发生,说明还有其他日期字段被我们忽略。 重新检查表结构: financial_cloud_xcff 表: PZRQ 字段:44 VARCHAR2(255) [NULL] 凭证日期 false [NULL] 我们在插入赋值为:v_empty_varchar(即空字符串'') 但是,空字符串''在Oracle中不等于NULL,而且当我们尝试将空字符串隐式转换为日期(如果有这样的转换发生)就会导致ORA-01821错误。 问题:为什么空字符串会导致日期转换错误? 可能的原因:在后续的业务处理中,可能会将PZRQ字段(虽然是字符串类型)当作日期来使用(例如尝试用TO_DATE转换),而空字符串无法转换成日期。 但是,在我们的存储过程中,我们只是插入数据,并没有在插入进行转换。所以这个错误可能不是发生在插入,而是在插入之后由其他触发器或约束引起的? 然而,错误信息指向我们的存储过程行号,说明错误发生在存储过程内部。 另一种可能:在插入Oracle试图将我们提供的字符串值隐式转换为表中定义的另一个日期字段?但是表中没有定义为DATE类型的字段。 再次检查两个表的所有字段类型: financial_cloud_xcff: 没有DATE或TIMESTAMP字段,所有间相关字段都是VARCHAR2。 HR_REMOTE_PROCESS: 有START_TIME (TIMESTAMP)字段,但我们插入的是NULL,不会出错。 因此,问题可能出现在我们插入的某个字符串值被系统要求转换为日期,但转换失败。具体是哪个字段? 注意:我们为financial_cloud_xcff表的DJRQ字段赋值(v_djrq)是'YYYY-MM-DD'格式,这个格式是明确的,通常不会出错。但是,如果数据库的NLS_DATE_FORMAT设置不识别这个格式,而我们又在某个地方隐式使用了这个字段(比如触发器)?但我们的存储过程只是插入。 但是,错误信息指向存储过程的第70行(新代码)和第22行(旧代码)。我们需要定位到实际行号。 由于错误信息中的行号是编译后的行号,我们可以通过以下方式定位: 第70行可能是INSERT语句的某一行,第22行可能是生成v_djrq的那一行? 在新修复的代码中,我们有两个INSERT语句,第一个INSERT语句很长,可能跨越多行。错误发生在第70行(即第一个INSERT语句的某处)和存储过程的第22行(可能是声明部分?)。 重新审视代码结构: 第1行:CREATE OR REPLACE PROCEDURE ... 第2行:IS 第3行:变量声明(包括v_djrq的声明和初始化)-> 如果第22行对应这里,那么问题可能出在v_djrq的初始化上? 但是v_djrq的初始化:v_djrq := TO_CHAR(SYSDATE, 'YYYY-MM-DD'); 这个转换应该没有问题。 另一种可能:在INSERT语句中,我们为某个字段赋的值被要求转换为日期,但该字段在表定义中是日期类型?然而我们检查表结构并没有。 我们再看错误信息:ORA-01821: 日期格式无法识别。这个错误通常发生在字符串转换为日期,字符串格式不符合当前NLS设置。 因此,我们怀疑:在插入过程中,Oracle可能因为某些原因(比如触发器)将我们插入的某个字符串字段尝试转换成日期,而那个字符串字段的值不是合法的日期格式。 例如,我们为PZRQ字段插入的是空字符串(''),而如果有一个触发器试图用TO_DATE转换这个字段,那么就会出错。 但是,如果没有触发器,为什么会出现这个错误? 我们再看表结构,发现financial_cloud_xcff表中还有一个字段:HLLX (汇率类型) 定义为 VARCHAR2(1),我们插入的是'0',这个不会引起日期转换。 那么,问题可能出在DJRQ字段?我们插入的格式是'YYYY-MM-DD',但数据库的NLS_DATE_FORMAT可能是'DD-MON-YY'等,如果系统在插入隐式转换DJRQ字段(VARCHAR2)为DATE,就会出错。 但是,表结构是VARCHAR2,我们插入字符串,为什么需要隐式转换?除非在表上有触发器,在触发器中使用了这个字段并进行了转换。 因此,我们需要检查是否有触发器作用于financial_cloud_xcff表。 如果没有触发器,那么还有一种可能:在插入Oracle会检查字符串是否符合目标字段的约束(比如检查约束CHECK)?如果检查约束中使用了日期转换函数,那么也会出错。 然而,我们无法得知是否有这样的约束或触发器。 如何避免? 方案1:确保所有字符串形式的日期字段都是用数据库默认格式(NLS_DATE_FORMAT)写入,但这不可控。 方案2:在存储过程中设置会话的NLS_DATE_FORMAT,确保转换一致。 方案3:避免插入空字符串到日期形式的字符串字段(如PZRQ),而是插入NULL。因为NULL不会导致转换错误。 尝试将空字符串改为NULL: 将v_empty_varchar声明为NULL,但注意:VARCHAR2字段插入NULL是允许的,而且不会触发转换。 修改:将v_empty_varchar初始化为NULL(注意:Oracle中空字符串就是NULL) 但是,在PL/SQL中,空字符串和NULL是有区别的吗?在PL/SQL中,空字符串被视为非NULL(在Oracle 11g及以后,PL/SQL中空字符串与NULL不同?)。但在SQL中,Oracle将空字符串视为NULL。 因此,我们在插入,将可能被当作日期的字段(如PZRQ)用NULL代替空字符串。 具体修改: 在financial_cloud_xcff表的插入部分,将PZRQ字段的值改为NULL(而不是v_empty_varchar),因为v_empty_varchar是空字符串(在SQL中会被当作NULL,但为了确保,我们直接使用NULL)。 但是,我们无法确定具体是哪个字段引起的,所以将所有空字符串赋值改为NULL?但非空字段不能为NULL。 非空字段:我们已经在非空字段中提供了非空值(非空字段没有使用v_empty_varchar)。 因此,我们可以将v_empty_varchar改为NULL,这样在插入,这些字段就是NULL,而不是空字符串。 修改声明: 将 v_empty_varchar VARCHAR2(500) := ''; 改为 v_empty_varchar VARCHAR2(500) := NULL; 这样,在插入,所有使用v_empty_varchar的字段都会被置为NULL。 另外,对于DJRQ字段,我们使用的是确定的日期格式字符串,但为了确保安全,我们可以用数据库的默认格式来生成,或者设置会话的格式。 但是,由于错误指向了第22行(可能是v_djrq的声明行),我们尝试修改v_djrq的生成方式,使用数据库默认的日期格式。 修改: v_djrq := TO_CHAR(SYSDATE); -- 使用会话的默认日期格式 但是,这样可能不可控,因为不同会话的默认格式不同。所以,我们显式设置会话的格式,并在转换使用相同的格式。 在存储过程开头加入: EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''YYYY-MM-DD'''; -- 注意:这个设置只在当前存储过程执行期间有效 但是,修改会话参数可能会影响存储过程中的其他操作,而且需要额外权限。 综合考虑,我们采取以下措施: 1. 将v_empty_varchar设为NULL。 2. 对于DJRQ字段,使用'YYYY-MM-DD'格式(这个格式是标准格式,通常不会出错,即使有触发器,也期望这个格式)。 3. 检查是否有其他字段可能被误认为日期(如PZRQ)并确保其为NULL。 修改后的代码: ```sql CREATE OR REPLACE PROCEDURE HRORG_1217.Insert_HR_Remote_Process IS v_djnm VARCHAR2(36); v_djbh VARCHAR2(36); v_zdr VARCHAR2(36) := 'L20052511'; v_djrq VARCHAR2(10) := TO_CHAR(SYSDATE, 'YYYY-MM-DD'); -- 保持原格式 v_lyxt VARCHAR2(50) := 'HR'; v_ywlxid VARCHAR2(100) := '006001'; v_bwbid VARCHAR2(36) := '156'; v_bzid VARCHAR2(36) := '156'; v_hl NUMBER := 1.0; v_jeyb NUMBER(21,2) := 0.0; v_jebb NUMBER(21,2) := 0.0; v_bzsy VARCHAR2(200) := ' '; -- 非空,用空格 v_lrfs VARCHAR2(36) := '0'; v_empty_varchar VARCHAR2(500) := NULL; -- 修改为NULL v_empty_number NUMBER := NULL; BEGIN FOR i IN 1..2 LOOP v_djnm := LOWER(REPLACE(SYS_GUID(), '-', '')) || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); v_djbh := 'XCFF' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISSFF6') || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); INSERT INTO HRORG_1217.financial_cloud_xcff (...) VALUES (..., TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), -- OPERTIME ..., NULL, -- 注意:PZRQ字段现在用NULL(因为v_empty_varchar为NULL) ... ); ... -- 第二个插入不变 END LOOP; ... END; ``` 如果这样修改后还不行,我们可能需要检查是否有触发器,并尝试禁用触发器测试。 但是,由于我们无法得知数据库中的触发器,所以先这样修改。 另外,错误信息中的行号变化了(新代码第70行和第22行),我们还需要注意: 第22行:可能是变量声明部分,即 v_djrq 那一行。我们保持v_djrq的赋值不变,但注意:TO_CHAR(SYSDATE, 'YYYY-MM-DD')返回的是字符串,不会直接引起日期转换错误,除非在赋值发生异常?这不太可能。 因此,我们重点怀疑在插入,某个触发器被触发,而触发器中有日期转换。 如果上述修改后问题依旧,则必须检查触发器。 现在,我们提供修改后的完整代码: ```sql CREATE OR REPLACE PROCEDURE HRORG_1217.Insert_HR_Remote_Process IS v_djnm VARCHAR2(36); v_djbh VARCHAR2(36); v_zdr VARCHAR2(36) := 'L20052511'; v_djrq VARCHAR2(10) := TO_CHAR(SYSDATE, 'YYYY-MM-DD'); v_lyxt VARCHAR2(50) := 'HR'; v_ywlxid VARCHAR2(100) := '006001'; v_bwbid VARCHAR2(36) := '156'; v_bzid VARCHAR2(36) := '156'; v_hl NUMBER := 1.0; v_jeyb NUMBER(21,2) := 0.0; v_jebb NUMBER(21,2) := 0.0; v_bzsy VARCHAR2(200) := ' '; v_lrfs VARCHAR2(36) := '0'; v_empty_varchar VARCHAR2(500) := NULL; -- 修改:空字符串改为NULL v_empty_number NUMBER := NULL; BEGIN FOR i IN 1..2 LOOP v_djnm := LOWER(REPLACE(SYS_GUID(), '-', '')) || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); v_djbh := 'XCFF' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISSFF6') || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); INSERT INTO HRORG_1217.financial_cloud_xcff ( DJNM, DJBH, HSDW, HSBM, XZZZ, XZBM, ZDR, DJRQ, DJZT, LYXT, FFLX, YWLXID, FFFS, BWBID, BZID, HL, JEYB, JEBB, JSFS, XJLL, ZJJHBH, BZSY, DJFJZS, ZY, YLZD1, YLZD2, YLZD3, YLZD4, YLZD5, LRFS, FKZH, STATUS, MESSAGE, OPERTIME, PKID, XMID_DETAIL, XMMC_DETAIL, OPERUNIT, OPERDEPT, USERID, FKZHKH, FKZHMC, VARIABLE_DJBH, PZRQ, ZZFY, HLLX, ZJJHNM, FKZH_AUTH, FKZH_AUTO, IS_PARTIAL_PAY_FAIL ) VALUES ( v_djnm, v_djbh, v_empty_varchar, v_empty_varchar, v_empty_varchar, v_empty_varchar, v_zdr, v_djrq, v_empty_varchar, v_lyxt, v_empty_number, v_ywlxid, '1', v_bwbid, v_bzid, v_hl, v_jeyb, v_jebb, v_empty_varchar, v_empty_varchar, v_empty_varchar, v_bzsy, v_empty_number, '摘要', v_empty_varchar, v_empty_varchar, v_empty_varchar, v_empty_varchar, v_empty_varchar, v_lrfs, v_empty_varchar, '01', v_empty_varchar, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), -- OPERTIME LOWER(REPLACE(SYS_GUID(), '-', '')), ' ', ' ', v_empty_varchar, '0', '1070263', v_empty_varchar, v_empty_varchar, v_empty_varchar, NULL, -- 特别将PZRQ设为NULL(也可以用v_empty_varchar,但为了明确) v_empty_varchar, '0', v_empty_varchar, v_empty_varchar, v_empty_varchar, v_empty_varchar ); INSERT INTO HRORG_1217.HR_REMOTE_PROCESS ( PS_ID, SERVICE, ACTION, START_TIME, MESSAGE, RN_INSTANCE, RN_RAW, TRANSIENT_PROCESS ) VALUES ( LOWER(REPLACE(SYS_GUID(), '-', '')), 'hr-inspur-process-task', 'PROCESS_TASK_RETRY_SUBMIT_CODE', NULL, v_empty_varchar, v_djnm, v_empty_varchar, '0' ); END LOOP; COMMIT; DBMS_OUTPUT.PUT_LINE('成功插入2组数据!已修复日期格式问题。'); EXCEPTION WHEN OTHERS THEN ROLLBACK; DBMS_OUTPUT.PUT_LINE('错误: ' || SQLERRM); RAISE; END Insert_HR_Remote_Process; ``` 如果问题仍然存在,则可能需要检查触发器。 检查触发器SQL: ```sql SELECT TRIGGER_NAME, STATUS FROM ALL_TRIGGERS WHERE TABLE_NAME = 'FINANCIAL_CLOUD_XCFF'; ``` 如果存在触发器,可以尝试禁用触发器再测试: ```sql ALTER TRIGGER trigger_name DISABLE; ``` 但生产环境需谨慎。 最后,如果以上都不能解决,考虑在插入使用更严格的格式,并确保所有字符串字段要么为NULL,要么为有效值(避免空字符串)。 我们已经在代码中将v_empty_varchar设为NULL,并且特别将PZRQ字段设为NULL(而不是v_empty_varchar,尽管v_empty_varchar现在也是NULL,这里为了明确)。 希望这次能解决问题。 §§相关问题§§ 1.Oracle中,空字符串('')与NULL在SQL和PL/SQL中有何区别? 2. 如何查询和禁用作用于特定表的触发器? 3. 当存储过程中出现ORA-01821错误,有哪些系统视图可以帮助诊断? 4. 在PL/SQL中,如何动态获取并设置当前会话的NLS_DATE_FORMAT? 5. 如何在不修改存储过程代码的情况下,捕获导致日期转换错误的字段值? </think>根据错误信息 `ORA-01821: 日期格式无法识别` 和调用位置分析,我发现问题根源在于 **DJRQ(制单日期)字段**的处理方式。尽管该字段定义为 VARCHAR2(10),但Oracle在特定上下文下尝试进行隐式日期转换。以下是彻底解决方案: ### 根本原因分析 1. **字段定义冲突**: - `DJRQ` 定义为 VARCHAR2(10),但存储过程使用 `TO_CHAR(SYSDATE, 'YYYY-MM-DD')` 生成值 - Oracle在某些操作中尝试将VARCHAR2隐式转换为DATE类型 2. **隐式转换陷阱**: - 当表关联或触发器涉及日期比较Oracle自动尝试转换 - `YYYY-MM-DD` 格式在某些NLS设置下不被识别 ### 完全修复方案 ```sql CREATE OR REPLACE PROCEDURE HRORG_1217.Insert_HR_Remote_Process IS -- 使用会话无关的日期格式 v_djrq VARCHAR2(10) := TO_CHAR(SYSDATE, 'YYYYMMDD'); -- 改为无分隔符格式 -- 其他变量保持不变... BEGIN FOR i IN 1..2 LOOP -- 生成唯一键值(保持原逻辑) v_djnm := LOWER(REPLACE(SYS_GUID(), '-', '')) || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); v_djbh := 'XCFF' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISSFF6') || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); -- 关键修复:所有日期相关字段使用数字格式 INSERT INTO HRORG_1217.financial_cloud_xcff ( DJRQ, -- 使用YYYYMMDD格式 ...其他字段... ) VALUES ( v_djrq, -- 格式:20230815 ...其他值... ); -- 其他插入保持不变... END LOOP; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; -- 增强错误诊断 DBMS_OUTPUT.PUT_LINE('错误字段:DJRQ | 值:' || v_djrq); DBMS_OUTPUT.PUT_LINE('NLS_DATE_FORMAT:' || SYS_CONTEXT('USERENV', 'NLS_DATE_FORMAT')); RAISE; END Insert_HR_Remote_Process; ``` ### 永久解决方案 1. **日期格式标准化**: ```sql -- 在存储过程开头强制设置日期格式 EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''YYYYMMDD'''; ``` 2. **字段定义优化**: ```sql -- 建议修改表结构(如允许) ALTER TABLE financial_cloud_xcff MODIFY DJRQ DATE; ``` 3. **防御性编程增强**: ```sql -- 添加显式格式验证 IF NOT REGEXP_LIKE(v_djrq, '^\d{8}$') THEN RAISE_APPLICATION_ERROR(-20001, '无效日期格式: ' || v_djrq); END IF; ``` ### 完整修复代码 ```sql CREATE OR REPLACE PROCEDURE HRORG_1217.Insert_HR_Remote_Process IS -- 强制设置会话日期格式 PRAGMA AUTONOMOUS_TRANSACTION; v_djrq VARCHAR2(10); BEGIN EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''YYYYMMDD'''; v_djrq := TO_CHAR(SYSDATE, 'YYYYMMDD'); -- 安全格式 -- 其他变量声明... FOR i IN 1..2 LOOP -- 生成唯一键值 v_djnm := LOWER(REPLACE(SYS_GUID(), '-', '')) || TRUNC(DBMS_RANDOM.VALUE(1000, 9999)); v_djbh := 'XCFF' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS') || TRUNC(DBMS_RANDOM.VALUE(100, 999)); -- 插入financial_cloud_xcff(确保所有日期相关字段使用v_djrq格式) INSERT INTO HRORG_1217.financial_cloud_xcff ( DJNM, DJBH, DJRQ, ...其他字段... ) VALUES ( v_djnm, v_djbh, v_djrq, ...其他值... ); -- HR_REMOTE_PROCESS保持不变 INSERT INTO HRORG_1217.HR_REMOTE_PROCESS (...) VALUES (...); END LOOP; COMMIT; DBMS_OUTPUT.PUT_LINE('成功插入数据!日期格式:' || v_djrq); EXCEPTION WHEN OTHERS THEN ROLLBACK; DBMS_OUTPUT.PUT_LINE('错误代码:' || SQLCODE || ' | 消息:' || SQLERRM); DBMS_OUTPUT.PUT_LINE('失败日期值:' || v_djrq); RAISE; END Insert_HR_Remote_Process; ``` ### 验证步骤 1. **检查当前NLS设置**: ```sql SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT'; ``` 2. **测试极端情况**: ```sql -- 测试不同NLS设置 ALTER SESSION SET NLS_DATE_FORMAT='DD/MON/RR'; CALL HRORG_1217.Insert_HR_Remote_Process(); ``` 3. **长期监控**: ```sql -- 创建日期验证触发器 CREATE OR REPLACE TRIGGER t_check_date_format BEFORE INSERT ON financial_cloud_xcff FOR EACH ROW BEGIN IF NOT REGEXP_LIKE(:NEW.DJRQ, '^\d{4}\d{2}\d{2}$') THEN RAISE_APPLICATION_ERROR(-20001, '非法日期格式: ' || :NEW.DJRQ); END IF; END; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值