create or replace trigger "PHARMACY".DRUG_PRESC_DETAIL_TRAC_INSERT before insert on "PHARMACY"."DRUG_PRESC_DETAIL_TRAC" for each row declare ls_yb_code char(50); ls_fyss char(50); ls_kfys char(50); ls_zydm char(50); ls_zydm2 char(50); begin if :new.MED_LIST_CODG is null or :new.MED_LIST_CODG='' then Select nvl(a.insur_item_code,'*') Into ls_yb_code From insurance.his_vs_insur_national a Where a.item_code = :new.DRUG_CODE And a.item_spec = :new.PACKAGE_SPEC||:new.FIRM_ID And a.insur_charge_type = '国家医保' and rownum = 1; else ls_yb_code := '*'; end if; select c.prescribed_by,c.dispensing_provider into ls_fyss,ls_kfys from DRUG_PRESC_MASTER c Where c.PRESC_DATE=:new.PRESC_DATE And c.presc_no = :new.presc_no; Select y.yb_14 into ls_zydm From staff_dict y Where y.name = ls_kfys And y.yb_14 is Not Null; Select y.yb_14 into ls_zydm2 From staff_dict y Where y.name = ls_kfys And y.yb_14 is Not Null; if :new.PRSC_DR_NAME is null then :new.PRSC_DR_NAME :=ls_kfys; end if; if :new.PHAR_PRAC_CERT_NO is null then :new.PHAR_PRAC_CERT_NO := ls_zydm2; end if; :new.MED_LIST_CODG := ls_yb_code; end ; 这个处方写有什么问题获取时没有数据了
时间: 2025-06-13 09:21:24 浏览: 12
<think>嗯,用户给了一个Oracle触发器的代码,说在获取数据时没有数据了。我需要仔细分析这段代码,找出可能的问题。
首先,先看触发器的结构。这是一个BEFORE INSERT触发器,作用在DRUG_PRESC_DETAIL_TRAC表上。主要逻辑是在插入新记录前,根据条件设置某些字段的值。
接下来,代码里的变量声明部分没问题,都是CHAR类型。然后第一个IF判断是如果MED_LIST_CODG为空,就执行一个SELECT查询到ls_yb_code。这里的问题可能出在查询的条件或者表的数据是否存在。例如,insurance.his_vs_insur_national表中是否存在符合条件的记录。特别是item_spec的拼接,是否和表中的数据匹配?如果这里没有找到数据,会引发NO_DATA_FOUND异常,但原代码里没有异常处理,这可能导致触发器执行失败,从而插入操作被回滚。
然后是SELECT INTO语句获取ls_fyss和ls_kfys,从DRUG_PRESC_MASTER表中根据PRESC_DATE和presc_no查找。如果这个表里没有对应的记录,同样会触发NO_DATA_FOUND异常,导致插入失败。但用户提到的是“获取时没有数据了”,可能是指查询结果为空,但这里如果没有数据的话,触发器会报错,而不仅仅是数据为空。不过用户可能没有看到错误信息,或者应用程序处理了异常,导致看起来没有数据。
接下来两次从staff_dict表查询yb_14到ls_zydm和ls_zydm2,这里用了相同的条件,可能是个笔误,应该是ls_fyss和ls_kfys吗?比如第二个查询应该用ls_fyss?如果ls_kfys在staff_dict中没有对应的记录,或者yb_14为空,那这两个SELECT INTO也会抛出异常。特别是如果ls_kfys的值在staff_dict中不存在,就会导致NO_DATA_FOUND异常,整个触发器失败,插入操作被阻止。
然后是一些赋值逻辑,如果PRSC_DR_NAME为空,则设置为ls_kfys;PHAR_PRAC_CERT_NO为空则设为ls_zydm2。最后设置MED_LIST_CODG为ls_yb_code。
可能的问题点:
1. 缺少异常处理,当SELECT INTO没有找到数据时会抛出异常,导致插入失败,而用户可能没有正确处理这个错误,导致数据无法插入,看起来像是没有数据。
2. 查询staff_dict时两次用了相同的条件,可能应该是不同的变量?比如ls_fyss和ls_kfys?
3. 在查询insurance表时,item_spec的拼接是否正确?比如:new.PACKAGE_SPEC和FIRM_ID是否有可能为NULL,导致拼接后的条件不匹配表中的数据?
4. 使用ROWNUM=1时,如果有多个匹配记录,可能随机取了一个,但期望的是否有特定顺序?
可能的解决方案:
1. 添加异常处理,特别是NO_DATA_FOUND和TOO_MANY_ROWS,避免触发器抛出错误。
2. 检查两次对staff_dict的查询是否有误,是否应该使用不同的变量。
3. 确认查询条件中的字段拼接是否正确,是否需要处理NULL值。
4. 在SELECT语句中使用ORDER BY确保正确的记录被选取,特别是在使用ROWNUM=1时。</think>该触发器可能存在以下问题导致获取数据失败:
$$1. \textbf{未处理NO\_DATA\_FOUND异常}$$
- 所有`SELECT...INTO`语句未捕获`NO_DATA_FOUND`异常,当查询无结果时触发错误
- 示例:若`insurance.his_vs_insur_national`表中无匹配记录,插入操作会直接失败
$$2. \textbf{重复的staff\_dict查询}$$
```sql
-- 两个相同查询可能应为不同条件
Select y.yb_14 into ls_zydm From staff_dict y Where y.name = ls_kfys; -- 应检查变量名是否正确
Select y.yb_14 into ls_zydm2 From staff_dict y Where y.name = ls_kfys; -- 疑似应使用ls_fyss?
```
$$3. \textbf{字段逻辑缺陷}$$
- `item_spec`拼接逻辑:`:new.PACKAGE_SPEC||:new.FIRM_ID`
若任一字段为NULL会导致拼接结果为NULL,与`a.item_spec`无法匹配
$$4. \textbf{缺乏排序控制}$$
```sql
Select nvl(a.insur_item_code,'*')
From insurance.his_vs_insur_national a
Where ...
and rownum = 1; -- 缺少ORDER BY可能导致取到随机记录
```
$\textbf{建议修改方案:}$
```sql
CREATE OR REPLACE TRIGGER "PHARMACY".DRUG_PRESC_DETAIL_TRAC_INSERT
BEFORE INSERT ON "PHARMACY"."DRUG_PRESC_MASTER_TRAC"
FOR EACH ROW
DECLARE
-- 变量声明保持不变
BEGIN
-- 添加异常处理模块
BEGIN
IF :new.MED_LIST_CODG IS NULL THEN
SELECT MAX(a.insur_item_code) KEEP (DENSE_RANK FIRST ORDER BY a.update_date DESC)
INTO ls_yb_code
FROM insurance.his_vs_insur_national a
WHERE a.item_code = :new.DRUG_CODE
AND a.item_spec = NVL(:new.PACKAGE_SPEC,'')||NVL(:new.FIRM_ID,'')
AND a.insur_charge_type = '国家医保';
ELSE
ls_yb_code := '*';
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ls_yb_code := '*';
END;
-- 添加嵌套块处理主表查询
BEGIN
SELECT c.prescribed_by, c.dispensing_provider
INTO ls_fyss, ls_kfys
FROM DRUG_PRESC_MASTER c
WHERE c.PRESC_DATE = :new.PRESC_DATE
AND c.presc_no = :new.presc_no;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20001, '处方主记录不存在');
END;
-- 添加员工校验逻辑
IF ls_kfys IS NOT NULL THEN
BEGIN
SELECT MAX(y.yb_14)
INTO ls_zydm
FROM staff_dict y
WHERE y.name = ls_kfys;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ls_zydm := NULL;
END;
END IF;
-- 最终赋值增加NVL保护
:new.MED_LIST_CODG := NVL(ls_yb_code,'*');
:new.PRSC_DR_NAME := NVL(:new.PRSC_DR_NAME, ls_kfys);
:new.PHAR_PRAC_CERT_NO := NVL(:new.PHAR_PRAC_CERT_NO, ls_zydm);
END;
```
$\textbf{关键优化点:}$
1. 增加异常处理块捕获`NO_DATA_FOUND`
2. 使用`NVL`处理空字段拼接问题
3. 通过`MAX() KEEP (DENSE_RANK FIRST...)`实现可靠排序取值
4. 对关键字段增加空值保护
5. 分离不同业务的异常处理逻辑
6. 对主表查询失败明确抛出业务错误
建议检查:
1. `DRUG_PRESC_MASTER`表中是否存在对应`PRESC_DATE`和`presc_no`的记录
2. `staff_dict`表中`name`字段是否与`ls_kfys`完全匹配(注意空格等特殊字符)
3. `PACKAGE_SPEC`和`FIRM_ID`的拼接结果是否与`insurance`表中存储格式一致
阅读全文
相关推荐















