Суть проблемы заключается в том, что нам нужно преобразовать значения из одной системы счисления (целые, числовые) в другую (имена столбцов, буквы), поскольку мы не можем просто «добавить 1» к серии имен столбцов вДля того, чтобы «сдвинуть их вправо», как в электронной таблице.Для выполнения преобразований я предлагаю 2 функции.(Предостережение: следующий код является просто сырой версией 0.01!)
-- take a spreadsheet column name
-- find and return an integer that represents the column's position
-- eg 'A' -> 1, 'Z'-> 26, 'AA' -> 27, 'AMJ' -> 1024
create or replace function alphaToInt( colname varchar2 )
return number
is
alphabet constant varchar2( 26 ) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ;
numberbase number := 26 ;
lettervalue number := 0 ;
currentletter varchar2( 1 ) := '' ;
currentpos number := 0 ;
posval number := 0 ;
result number := 0 ;
begin
for i in 1 .. length( colname )
loop
currentletter := substr( colname, i * -1, 1 ) ;
currentpos := instr( alphabet, currentletter ) ;
posval := power( numberbase, i - 1 ) ;
result := result + ( posval * currentpos ) ;
end loop;
return result ;
end;
/
-- SQL> select alphaToInt( 'AA' ) from dual ;
-- ALPHATOINT('AA')
-- ----------------
-- 27
Для обратного действия вы можете использовать что-то вроде ...
-- take an integer
-- find and return its corresponding spreadsheet column name
create or replace function intToAlpha( colnumber number )
return varchar2
is
base number := 26 ;
remaining number := colnumber ;
remainder number := 0 ;
resultstring varchar2( 4000 ) := '' ;
begin
while remaining > 0
loop
remainder := mod( remaining - 1, base ) ;
resultstring := chr( 65 + remainder ) || resultstring ;
remaining := trunc( ( remaining - remainder ) / base ) ;
end loop;
return resultstring ;
end;
/
-- SQL> select intToAlpha( 1024 ) from dual ;
-- INTTOALPHA(1024)
-- -----------------
-- AMJ
Таблица дляtesting
create table mytable (
mxp_id number
, mx_id varchar2( 64 )
, tb_src varchar2( 64 )
, descr varchar2( 64 )
, col_loc char(3)
);
insert into mytable( mxp_id, mx_id, tb_src, descr, col_loc)
select 1 as MXP_ID, 'MX3' as MX_ID, 'MB_SHEET_ROW' as TB_SRC
, 'TEST' as DESCR, 'APS' as COL_LOC from dual union all
select 1, 'MX1', 'MB_SHEET_ROW', 'DEV', 'APT' from dual union all
select 1, 'MX120', 'MB_SHEET_ROW', 'PROD','APU' from dual union all
select 1, 'MX5', 'MB_SHEET_ROW', 'SET', 'APV' from dual union all
select 1, 'MX6', 'MB_SHEET_ROW', 'CHECK','APW' from dual union all
select 1, 'MX54', 'MB_SHEET_ROW', 'WHILE','APX' from dual union all
select 1, 'MX14', 'MB_SHEET_ROW', 'DO', 'APY' from dual union all
select 1, 'MX2', 'MB_SHEET_ROW', 'FOR', 'APZ' from dual;
Теперь мы имеем следующую ситуацию:
SQL> select * from mytable ;
MXP_ID MX_ID TB_SRC DESCR COL_LOC
1 MX3 MB_SHEET_ROW TEST APS
1 MX1 MB_SHEET_ROW DEV APT
----------------------------------------- <-- want to insert here.
1 MX120 MB_SHEET_ROW PROD APU
1 MX5 MB_SHEET_ROW SET APV
1 MX6 MB_SHEET_ROW CHECK APW
1 MX54 MB_SHEET_ROW WHILE APX
1 MX14 MB_SHEET_ROW DO APY
1 MX2 MB_SHEET_ROW FOR APZ
Не уверен, содержит ли столбец MX_ID уникальные значения.Таким образом, добавьте столбец id для хорошей меры.
alter table mytable
add id_ raw( 16 ) default sys_guid() ;
-- Table MYTABLE altered.
Следующий MERGE использует наши функции и изменяет все col_locs "после" столбца APU.
merge into mytable M
using (
select id_, mxp_id, mx_id, tb_src, descr, col_loc
from mytable
where col_loc >= 'APU'
) M2
on ( M.id_ = M2.id_ )
when matched then
update set col_loc = inttoalpha( alphatoint( col_loc ) + 1 )
;
-- 6 rows merged.
Вы, вероятно, знаете, что строкитаблица базы данных не "упорядочена", как строки таблицы.Помните об этом, вставляя новые строки.
insert into mytable ( mxp_id, mx_id, tb_src, descr, col_loc )
values ( 1, 'MX_NEW(!)', 'MB_SHEET_ROW', 'NEW_ENTRY', 'APU' ) ;
-- 1 row inserted.
Таблица теперь содержит:
select * from mytable order by col_loc;
MXP_ID MX_ID TB_SRC DESCR COL_LOC ID_
1 MX3 MB_SHEET_ROW TEST APS 6CD1B226D8CE12DAE0530100007F80CA
1 MX1 MB_SHEET_ROW DEV APT 6CD1B226D8CF12DAE0530100007F80CA
1 MX_NEW(!) MB_SHEET_ROW NEW_ENTRY APU 6CD1B226D8D612DAE0530100007F80CA
1 MX120 MB_SHEET_ROW PROD APV 6CD1B226D8D012DAE0530100007F80CA
1 MX5 MB_SHEET_ROW SET APW 6CD1B226D8D112DAE0530100007F80CA
1 MX6 MB_SHEET_ROW CHECK APX 6CD1B226D8D212DAE0530100007F80CA
1 MX54 MB_SHEET_ROW WHILE APY 6CD1B226D8D312DAE0530100007F80CA
1 MX14 MB_SHEET_ROW DO APZ 6CD1B226D8D412DAE0530100007F80CA
1 MX2 MB_SHEET_ROW FOR AQA 6CD1B226D8D512DAE0530100007F80CA
При наличии двух функций вам нужно только MERGE и INSERT при добавлении нового столбца электронной таблицы.Вы могли бы написать небольшую процедуру, которая сделает оба шага за вас.