Обновить таблицу оракула с предыдущим значением столбца

Anita Prasad спросил: 28 апреля 2018 в 09:38 в: excel

У меня есть таблица MyTable в оракуле:

MXP_ID         MX_ID    TB_SRC          DESC    COL_LOC
1              MX3      MB_SHEET_ROW    TEST    APS
1              MX1      MB_SHEET_ROW    DEV     APT
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

Это таблица excel, в которой поле colloc указывает разные столбцы: Это выражение excel будет:

APS APT APU     APV APW APX     APY     APZ
MX3 MX1 MX120   MX5 MX6 MX54    MX14    MX2

Если я вставляю новый столбец в вышеперечисленное excel после столбца APT, тогда в результирующем excel MX120 будет перемещаться в столбец APV и т. д.

APS APT APU      APV    APW APX APY     APZ     AQA
MX3 MX1 MX_NEW  MX120   MX5 MX6 MX54    MX14    MX2

Итак, соответствующая таблица в oracle будет изменена на: MyTable:

MXP_ID  MX_ID   TB_SRC         DESC       COL_LOC
1       MX3    MB_SHEET_ROW     TEST        APS
1       MX1     MB_SHEET_ROW    DEV         APT
1       MX_NEW  MB_SHEET_ROW    NEW_ENTRY   APU
1       MX120   MB_SHEET_ROW    PROD        APV
1       MX5    MB_SHEET_ROW      SET        APW
1       MX6     MB_SHEET_ROW    CHECK       APX
1       MX54    MB_SHEET_ROW    WHILE        APY
1       MX14    MB_SHEET_ROW    DO          APZ
1       MX2    MB_SHEET_ROW     FOR         AQA

Как автоматизировать этот процесс в oracle, чтобы каждая строка, вставленная в середину, сдвиньте COL_LOC в следующий столбец, как в excel.

Я использовал этот запрос, чтобы найти номера столбцов, соответствующие расположению столбца. Но я не знаю, как я могу обновить расположение столбцов, чтобы указать на следующий столбец.

SELECT MXP_ID, MX_ID , TB_SRC , DESC, COL_LOC ,
To_Number(
   case substr(COL_LOC,1,1)        when 'A' then 1
     when 'B' then 2
     when 'C' then 3
     when 'D' then 4
     when 'E' then 5
     when 'F' then 6
     when 'G' then 7
     when 'H' then 8
     when 'I' then 9
     when 'J' then 10
     when 'K' then 11
     when 'L' then 12
     when 'M' then 13
     when 'N' then 14
     when 'O' then 15
     when 'P' then 16
     when 'Q' then 17
     when 'R' then 18
     when 'S' then 19
     when 'T' then 20
     when 'U' then 21
     when 'V' then 22
     when 'W' then 23
     when 'X' then 24
     when 'Y' then 25
     when 'Z' then 26       End  ||   case substr(COL_LOC,2,1)
     when 'A' then 27
     when 'B' then 28
     when 'C' then 29
     when 'D' then 30
     when 'E' then 31
     when 'F' then 32
     when 'G' then 33
     when 'H' then 34
     when 'I' then 35
     when 'J' then 36
     when 'K' then 37
     when 'L' then 38
     when 'M' then 39
     when 'N' then 40
     when 'O' then 41
     when 'P' then 42
     when 'Q' then 43
     when 'R' then 44
     when 'S' then 45
     when 'T' then 46
     when 'U' then 47
     when 'V' then 48
     when 'W' then 49
     when 'X' then 50
     when 'Y' then 51
     when 'Z' then 52    
   End  ||   case substr(COL_LOC,3,1)        when 'A' then 52.3
     when 'B' then 53
     when 'C' then 54
     when 'D' then 55
     when 'E' then 56
     when 'F' then 57
     when 'G' then 58
     when 'H' then 59
     when 'I' then 60
     when 'J' then 61
     when 'K' then 62
     when 'L' then 63
     when 'M' then 64
     when 'N' then 65
     when 'O' then 66
     when 'P' then 67
     when 'Q' then 68
     when 'R' then 69
     when 'S' then 70
     when 'T' then 71
     when 'U' then 72
     when 'V' then 73
     when 'W' then 74
     when 'X' then 75
     when 'Y' then 76
     when 'Z' then 77   End)  as Column_number
FROM MyTable
order by Column_number;

1 ответ

stefan ответил: 28 апреля 2018 в 04:38

Ядро проблемы, похоже, состоит в том, что нам нужно преобразовать значения из одной числовой системы (целочисленной, числовой) в другую (имена столбцов, буквы), поскольку мы не можем просто "добавить 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 

Таблица для тестирования

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 уникальные значения. Таким образом, добавьте столбец идентификатора для хорошей меры.

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 при добавлении новой таблицы электронных таблиц. Возможно, вы могли бы написать небольшую процедуру, которая сделает для вас оба действия.