假设您希望 ID2 值与 ID1 值的顺序相同,并且没有重复的 ID1 值,您可以通过使用带有合适窗口子句的分析函数来执行此操作而无需序列:
select name, dob, id1,
100 + dense_rank() over (order by trunc(id1))
+ dense_rank() over (partition by trunc(id1) order by id1)/10
as id2
from table1;
NAME DOB ID1 ID2
----- ---------- ---------- ----------
JIM 1991-11-30 23.1 101.1
JIM 1991-11-30 23.2 101.2
JIM 1991-11-30 23.3 101.3
TOM 1993-12-30 30.1 102.1
TOM 1993-12-30 30.2 102.2
HENRY 1994-12-03 34.1 103.1
HENRY 1994-12-03 34.2 103.2
7 rows selected.
然后您可以将该生成的表用作合并语句的一部分:
merge into table1
using (
select name, dob, id1,
100 + dense_rank() over (order by trunc(id1))
+ dense_rank() over (partition by trunc(id1) order by id1)/10
as id2
from table1
) tmp on (tmp.id1 = table1.id1)
when matched then
update set table1.id2 = tmp.id2;
7 rows merged.
select * from table1;
NAME DOB ID1 ID2
----- ---------- ---------- ----------
JIM 1991-11-30 23.1 101.1
JIM 1991-11-30 23.2 101.2
JIM 1991-11-30 23.3 101.3
TOM 1993-12-30 30.1 102.1
TOM 1993-12-30 30.2 102.2
HENRY 1994-12-03 34.1 103.1
HENRY 1994-12-03 34.2 103.2
7 rows selected.
db<>fiddle
如果 ID2 不需要与 ID1 相关,那么您可以随意订购:
merge into table1
using (
select name, dob, id1,
100 + dense_rank() over (order by name, dob)
+ dense_rank() over (partition by name, dob order by id1)/10
as id2
from table1
) tmp on (tmp.id1 = table1.id1)
when matched then
update set table1.id2 = tmp.id2;
select * from table1;
NAME DOB ID1 ID2
----- ---------- ---------- ----------
JIM 1991-11-30 23.1 102.1
JIM 1991-11-30 23.2 102.2
JIM 1991-11-30 23.3 102.3
TOM 1993-12-30 30.1 103.1
TOM 1993-12-30 30.2 103.2
HENRY 1994-12-03 34.1 101.1
HENRY 1994-12-03 34.2 101.2
这只有在小数部分不超过 0.9 时才会按原样工作;但是如果确实如此,则很难解释这些值(因为 23.10 与 23.1 相同)。
我还假设这是一次性更新,您不打算在以后的插入中使用该序列;目前尚不清楚您将如何管理它 - 如果名称/DOB 尚不存在,您只想获取下一个序列值,如果存在,您将需要找到最高的现有 ID 并将 0.1 添加到它.无论哪种方式,您都必须序列化插入以防止冲突或差异。
它实际上进入了 ID1 值为 23.10、23.11 而 ID2 将它们显示为 101.1、101.1 的情况。
...我尝试将其除以 100,并且值 >= .11 小数位的问题已解决,但对于 .10 和 .20,它仍显示为 .1 和 .2。
这表明两个 ID 值都是字符串而不是数字。如果是这样,您仍然可以使用排名函数,但将生成的两个数字视为字符串并将它们连接在一起:
merge into table1
using (
select name, dob, id1,
to_char(100 + dense_rank() over (order by name, dob))
||'.'||
dense_rank() over (partition by name, dob
order by to_number(substr(id1, instr(id1, '.') + 1)))
as id2
from table1
) tmp on (tmp.id1 = table1.id1)
when matched then
update set table1.id2 = tmp.id2;
With some additional base data that gives you:
select * from table1;
NAME DOB ID1 ID2
----- ---------- ---------- ----------
JIM 1991-11-30 23.1 103.1
JIM 1991-11-30 23.2 103.2
JIM 1991-11-30 23.3 103.3
TOM 1993-12-30 30.1 104.1
TOM 1993-12-30 30.3 104.2
HENRY 1993-12-30 34.1 101.1
HENRY 1994-12-03 34.5 102.1
HENRY 1994-12-03 34.6 102.2
HENRY 1994-12-03 34.7 102.3
HENRY 1994-12-03 34.8 102.4
HENRY 1994-12-03 34.9 102.5
HENRY 1994-12-03 34.10 102.6
HENRY 1994-12-03 34.11 102.7
HENRY 1994-12-03 34.12 102.8
HENRY 1994-12-03 34.13 102.9
HENRY 1994-12-03 34.14 102.10
HENRY 1994-12-03 34.15 102.11
HENRY 1994-12-03 34.16 102.12
db<>fiddle
当然,这样做会使将 ID2 值视为数字或以有意义的方式对其进行排序变得非常尴尬;但是对于您的 ID1 值,情况必须已经如此。另一种方法可能是将第一部分乘以一个大数,比如 1000,然后加上第二部分 - 所以亨利最终得到 1020001 到 1010012。