DML 中的自增逻辑
auto increment logic in DML
我有两个表 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
您可以尝试以下方法:
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
与@Barbaros 的基本思想相同,但排列略有不同,第二个 table 的列大小增加,因此它可以容纳修改后的值:
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');
然后是同一个解析函数,如果你不介意重复它,在一个层次上,并在partition-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
如果您在真实场景中实际上有更多列,并且原始 table 中还有另一个非 PK 列,您想要影响历史记录行的递增顺序,您可以在函数的 order by
而不是 null
,这实际上只是一个虚拟占位符。
如果它需要在多次插入时继续做同样的事情(这表明数据模型问题甚至比原始要求更严重)那么您也需要计算历史记录中的现有匹配项 table .
从与之前相同的原始数据和空历史记录开始table:
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.
可能有一些方法可以对其进行优化,这样您就不必经常访问历史记录 table,但这可能会给您一个工作起点。
like
的使用实际上意味着这仅在文本始终具有相同长度的情况下才有效,或者至少您不能拥有其他值的扩展值;否则你会得到比你想要的更多的比赛。至少从您的示例数据来看,这看起来不是问题。如果需要,您可以通过切换到 regexp_like
来解决这个问题,具体取决于您的实际数据。
我有两个表 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
您可以尝试以下方法:
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
与@Barbaros 的基本思想相同,但排列略有不同,第二个 table 的列大小增加,因此它可以容纳修改后的值:
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');
然后是同一个解析函数,如果你不介意重复它,在一个层次上,并在partition-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
如果您在真实场景中实际上有更多列,并且原始 table 中还有另一个非 PK 列,您想要影响历史记录行的递增顺序,您可以在函数的 order by
而不是 null
,这实际上只是一个虚拟占位符。
如果它需要在多次插入时继续做同样的事情(这表明数据模型问题甚至比原始要求更严重)那么您也需要计算历史记录中的现有匹配项 table .
从与之前相同的原始数据和空历史记录开始table:
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.
可能有一些方法可以对其进行优化,这样您就不必经常访问历史记录 table,但这可能会给您一个工作起点。
like
的使用实际上意味着这仅在文本始终具有相同长度的情况下才有效,或者至少您不能拥有其他值的扩展值;否则你会得到比你想要的更多的比赛。至少从您的示例数据来看,这看起来不是问题。如果需要,您可以通过切换到 regexp_like
来解决这个问题,具体取决于您的实际数据。