我需要根据名称和DOB更新表中的列ID2值。我创建了一个oracle序列,并决定将值填充到ID2列中,但无法将逻辑合并到更新查询中。请查看我下面的代码,该代码用于对Name,DOB进行分组,并更新ID2,但我陷入了逻辑的中间。如果您在sql或plsql中有任何解决方案,那就可以了!谢谢。
CREATE SEQUENCE seq
MINVALUE 1
START WITH 100
INCREMENT BY 1;
UPDATE table1 SET ID2 = seq.nextval
where Name= ---NOT SURE WHAT TO DO ?
select count(*) from table1
group by NAME,DOB;
答案 0 :(得分:1)
假设您希望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.
如果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还不存在,则只希望获取下一个序列值;如果名称/ 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
当然,这样做会使将ID2值视为数字或以有意义的方式对其进行排序变得非常尴尬;但是对于您的ID1值,情况一定已经如此。一种替代方法是,将第一部分乘以一个大数字,例如1000,然后再加上第二部分-因此,亨利最终说出1020001至1010012。