DML中的自动递增逻辑

时间:2018-09-19 16:14:04

标签: sql oracle sql-insert

我有两个表test2和test_hist。我想将数据从test2加载到test_hist中,但是由于唯一的约束而失败。

CREATE TABLE TEST2 (ID NUMBER , TEXT VARCHAR2(10));
create table test_hist (id number , text varchar2(10) , constraint t_pk PRIMARY key (id , text));

INSERT INTO TEST2 VALUES(100 , '20180909-I');
INSERT INTO TEST2 VALUES(101 , '20180909-I');
INSERT INTO TEST2 VALUES(102 , '20180809-I');
INSERT INTO TEST2 VALUES(100 , '20180909-I');
COMMIT;

INSERT INTO test_hist SELECT ID , TEXT FROM TEST2;

只要要重复如下所示,我想在TEXT字段后附加自动递增编号。

expected OUTPUT 

ID         TEXT
100      20180909-I
101      20180909-I
102      20180809-I
100      20180909-I-1
100      20180909-I-2
102      20180809-I-1

谁能帮助我实现这一目标。 在此先感谢

如果我多次执行插入语句,则应使用自动增量文本将其插入到test_hist中。 例如

insert into test_hist
select id,
  text || case when row_number() over (partition by id, text order by null) > 1
          then (1 - row_number() over (partition by id, text order by null)) end
from test2;

9 rows inserted.

select *
from test_hist
order by id, text;

        ID TEXT        
---------- ------------
       100 20180909-I  
       100 20180909-I-1
       100 20180909-I-2
       100 20180909-I-3
       101 20180909-I  
       101 20180909-I-1
       102 20180809-I  
       102 20180809-I-1
       102 20180809-I-2 

2 个答案:

答案 0 :(得分:1)

您可以尝试以下方法:

select ID, text||decode(rn-1,0,null,'-'||(rn-1)) as text
from
(
with test2(rnk,ID,text) as
(
    select 1, 100 , '20180909-I' from dual union all
    select 2, 101 , '20180909-I' from dual union all
    select 3, 102 , '20180809-I' from dual union all
    select 4, 100 , '20180909-I' from dual union all
    select 5, 100 , '20180909-I' from dual union all
    select 6, 102 , '20180909-I' from dual
    )
    select t.ID, t.rnk, 
           t.text, row_number() over (partition by ID order by Text,ID) as rn
      from test2 t
)
 order by rn, rnk

Rextester Demo

答案 1 :(得分:1)

与@Barbaros相同的基本思想,但排列略有不同,并且第二张表的列大小增加了,因此可以容纳修改后的值:

create table test2 (
  id number, text varchar2(10)
);

create table test_hist (id number,
  text varchar2(12), -- increased size to 12; may need to be larger
  constraint t_pk primary key (id , text)
);

insert into test2 values(100 , '20180909-I');
insert into test2 values(101 , '20180909-I');
insert into test2 values(102 , '20180809-I');
insert into test2 values(100 , '20180909-I');
insert into test2 values(100 , '20180909-I');
insert into test2 values(102 , '20180809-I');

然后,如果不介意重复该分析功能,则将其放在一个级别,并在partitioning-by子句中包括所有PK列:

insert into test_hist
select id,
  text || case when row_number() over (partition by id, text order by null) > 1
          then (1 - row_number() over (partition by id, text order by null)) end
from test2;

6 rows inserted.

select *
from test_hist
order by id, text;

        ID TEXT        
---------- ------------
       100 20180909-I  
       100 20180909-I-1
       100 20180909-I-2
       101 20180909-I  
       102 20180809-I  
       102 20180809-I-1

如果实际情况中实际上有更多列,并且原始表中还有另一个非PK列想要影响历史记录行的递增顺序,则可以在函数的{{1}中使用它}而不是order by,它实际上只是一个虚拟占位符。


如果它需要在多个插入上继续做同样的事情(这表明数据模型问题甚至比原始要求还多),那么您还需要计算历史记录表中的现有匹配项。

从与以前相同的原始数据开始,并使用空的历史记录表:

null

并再次运行同一条语句:

insert into test_hist
select id,
  text || case when appearance > 1 then (1 - appearance) end
from (
  select t.id,
    t.text,
    row_number() over (partition by t.id, t.text order by null) + (
      select count(*) from test_hist th
      where th.id = t.id
      and th.text like t.text || '%'
    ) as appearance
  from test2 t
);

6 rows inserted.

select *
from test_hist
order by id, text;

        ID TEXT        
---------- ------------
       100 20180909-I  
       100 20180909-I-1
       100 20180909-I-2
       101 20180909-I  
       102 20180809-I  
       102 20180809-I-1

6 rows selected. 

可能有多种方法可以对其进行优化,因此您不必如此频繁地访问历史记录表,但这可以为您提供一个起点。

使用insert into test_hist select id, text || case when appearance > 1 then (1 - appearance) end from ( select t.id, t.text, row_number() over (partition by t.id, t.text order by null) + ( select count(*) from test_hist th where th.id = t.id and th.text like t.text || '%' ) as appearance from test2 t ); 6 rows inserted. select * from test_hist order by id, text; ID TEXT ---------- ------------ 100 20180909-I 100 20180909-I-1 100 20180909-I-2 100 20180909-I-3 100 20180909-I-4 100 20180909-I-5 101 20180909-I 101 20180909-I-1 102 20180809-I 102 20180809-I-1 102 20180809-I-2 102 20180809-I-3 12 rows selected. 实际上意味着只有在文本长度始终相同,或者至少您不能拥有作为其他值的扩展名的值时,此方法才有效。否则,您将获得比您想要的更多的比赛。至少从您的样本数据来看,这似乎不是问题。您可能可以通过根据实际数据切换到like来解决此问题。