Oracle下,有表X(a,b,c,d),有表y(a,b,c)。
insert into X(a, b, c, d)
select a, b, c, func_serial(a, b, c) as d
from Y;
func_serial函数的作用是,在X中查找是否存在a,b,c三个字段和传入的参数相同的记录行,如果有,则返回该行的d值,如果没有,则计算X中a,b两个字段和传入参数相同的组中不重复c值的个数count,返回count+1。
不过好像在Oracle中不能这么操作,报:
ORA-04091: 表 X 发生了变化, 触发器/函数不能读它
想问下,在Oracle中一般是怎么比较好的解决这个需求的?
【下面举例说明一下】
表X:
a | b | c | d |
---|---|---|---|
1 | 2 | 3 | 1 |
4 | 5 | 4 | 1 |
4 | 5 | 6 | 2 |
表Y:
a | b | c |
---|---|---|
1 | 2 | 3 |
1 | 2 | 4 |
1 | 2 | 5 |
4 | 5 | 7 |
7 | 8 | 9 |
希望把这样的数据插入X中:
a | b | c | d |
---|---|---|---|
1 | 2 | 3 | 1 |
1 | 2 | 4 | 2 |
1 | 2 | 5 | 3 |
4 | 5 | 7 | 3 |
7 | 8 | 9 | 1 |
目前是这么写的:
with distinct_X as (
select distinct a, b, c, d
from X
),
group_X as (
select a, b, count(distinct c) as cnt
from X
group by a, b
)
insert X(a, b, c, d)
select
m.a,
m.b,
m.c,
case nvl(n.d, ' ') when ' ' then
row_number() over (partition by m.a, m.b order by m.c) + nvl(o.cnt, 0)
else n.d end as d
from Y m
left join distinct_X n on m.a = n.a and m.b = n.b and m.c = n.c
left join group_X o on m.a = n.a and m.b = n.b
但是这样有个问题,就是新插入的a,b值相同的n行数据中如果有部分是存在既有d值的,那么其余新生成的d值会不连续,中间浪费了很多编号……
根据题主对问题描述的更新,
Y
是否可分为两部分分别处理:Y
中a, b, c
已经包含于X
,则直接取X.d
;将
Y
去除满足 (1) 的行后,剩下的部分按a, b
排序并取序号。注意此序号须跳过X
中对应同样a, b
的d
的最大值。