【发布时间】:2022-01-01 23:47:03
【问题描述】:
我正在尝试创建一个触发器,以便在将插入到另一个表中时自动生成并插入带有年份和月份 (YYYYMM) 的值到表中。
示例: 由于插入到表'original_table'中
create table original_table
(opt_value char(2),
low_value varchar2(24),
high_value varchar2(24));
create table new_values
(id_values varchar2(24),
yr_month number(6));
Insert into original_table(opt_value,low_value,high_value) values ('EQ', '1111111111', '1111111111');
Insert into original_table(opt_value,low_value,high_value) values ('BT', '2222222000', '2222222999');
Insert into original_table(opt_value,low_value,high_value) values ('BT', '3333333350', '3333333399');
原始表
| opt_value | low_value | high_value |
|---|---|---|
| EQ | 1111111111 | 1111111111 |
| BT | 2222222000 | 2222222999 |
| BT | 3333333350 | 3333333399 |
Obs:EQ 代表“相等”,BT 代表“介于”。当'EQ'只需要插入低或高其中一个值时,'BT'需要生成两个值之间的所有数字,然后插入到'new_values'表中。
table 'new_values' 应该得到:
新值
| id_values | yr_month |
|---|---|
| 1111111111 | 202111 |
| 2222222000 | 202111 |
| 2222222001 | 202111 |
| 2222222002 | 202111 |
| ... | ... |
| 2222222999 | 202111 |
| 3333333350 | 202111 |
| 3333333351 | 202111 |
| ... | ... |
| 3333333399 | 202111 |
我创建了一个可以工作的触发器,但我发现它有点慢,而且我不喜欢使用 BEFORE INSERT 语句,但不能使用 AFTER INSERT 而不会出现变异表错误。
create or replace TRIGGER TRG_NAME
BEFORE INSERT
ON original_table
FOR EACH ROW
BEGIN
IF :NEW.opt_value = 'BT' THEN
INSERT INTO new_values (id_values, yr_month)
with tab123 (h_value, l_value, y_month)
as (select :NEW.high_value, cast(:NEW.low_value as number) , to_char(trunc(sysdate), 'YYYYMM')
from original_table
union all
select h_value, l_value +1, y_month
from tab123
where l_value < h_value)
select distinct l_value, y_month
from tab123;
ELSIF :NEW.opt_value = 'EQ' THEN
INSERT INTO new_values (id_values, yr_month) values
( :NEW.high_value, to_char(add_months(trunc(sysdate), -1), 'YYYYMM'));
END IF;
END;
任何关于如何改进此代码的提示将不胜感激。
【问题讨论】:
-
该触发器将 所有 行从 original_table(联合其他)插入 new_values(BT 条件)。并且在每一个插入物上。因此,如果您有 10 个值并插入一个新值,它将在 new_values 中插入 11 行(+ 联合结果)。然后,当您添加一个额外的值时,它会插入 12 个值(+ 联合结果)这是预期的行为吗?
-
不,我已经更改了它,但忘记在我的草稿中更改,在最后一个选择上加上一个不同的。立即编辑。
-
没有。通常
DISTINCT在这里是一个可怕的解决方案。当您只需要一行时,您没有看到您自己通过读取表中的所有行来创建所有重复项吗?再次删除DISTINCT并将 CTE 中的from original_table更改为from dual。 -
当您从正在更改的表中读取数据时,您会收到一个变异表错误。奇怪的是,您在
AFTER INSERT触发器中而不是在BEFORE INSERT触发器中得到它。我会假设它们都会导致相同的错误,因为在这两种情况下,您都是从触发器中的触发表中读取的。好吧,这可能与只插入一行有关。如果您插入更多行,您可能会收到两个触发器变体的错误。而且,如果您按照我的建议删除表格,无论如何您可能会摆脱该错误。 -
附带说明:为什么将数值作为字符串存储在数据库中?这似乎没有意义。始终使用适当的数据类型将值存储在表中。然后,永远不要使用
CHAR;始终使用VARCHAR2。CHAR与VARCHAR2相比没有优势,只有劣势。
标签: sql oracle recursion plsql