Обновить таблицу в Oracle - PullRequest
0 голосов
/ 06 мая 2020

Мне нужно изменить столбцы таблиц типа CHAR на VARCHAR2, но они попросили меня сделать это автоматически, потому что это 100 таблиц. Один из способов обновить все столбцы таблицы в Oracle без необходимости помещать столбец за столбцом - использовать для извлечения столбцов из представления user_tables, но в этих таблицах есть данные, когда данные изменяют пробелы, которые обрабатывает CHAR справа также передаются в VARCHAR2, что мне нужно, так это обновить данные таблицы, применяя RTRIM, я сделал это с помощью набора обновлений таблицы column = rtrim (column); но они спрашивают меня, что обновление происходит не столбец за столбцом, а во всей таблице, так что это всего лишь запрос, есть ли способ этого добиться? Я погуглил и нашел только синтаксис, который я уже использую

1 Ответ

2 голосов
/ 06 мая 2020

Вы можете использовать SQL для генерации необходимых операторов. Минимальный пример:

CREATE TABLE t0 (i INT);
CREATE TABLE t1 (a CHAR(10), b NUMBER, c VARCHAR2(30), d CHAR(40));
INSERT INTO  t1 VALUES('a',1,'a','a');
CREATE TABLE t2 (x CHAR(10), y CHAR(20 CHAR), z CHAR(30 BYTE));
INSERT INTO  t2 VALUES('b','b','b');

SELECT 'UPDATE ' || table_name ||' SET ' || 
       LISTAGG(column_name||'=RTRIM('||column_name||')', ', ')
       WITHIN GROUP (ORDER BY column_id) || '; COMMIT;' as sql
  FROM user_tab_columns
 WHERE data_type='CHAR'
 GROUP BY table_name
 ORDER BY table_name;

Будет производить следующие операторы:

UPDATE T1 SET A=RTRIM(A), D=RTRIM(D); COMMIT;
UPDATE T2 SET X=RTRIM(X), Y=RTRIM(Y), Z=RTRIM(Z); COMMIT;

Аналогично,

SELECT 'ALTER TABLE '||table_name||' MODIFY ('||LISTAGG(
        column_name||
      ' VARCHAR2('||data_length||' '||DECODE(char_used,'B','BYTE','C','CHAR')||')', ', ') 
        WITHIN GROUP (ORDER BY column_id) ||');' as sql
  FROM user_tab_columns
 WHERE data_type='CHAR'
 GROUP BY table_name
 ORDER BY table_name;

даст

ALTER TABLE T1 MODIFY (A VARCHAR2(10 BYTE), D VARCHAR2(40 BYTE));
ALTER TABLE T2 MODIFY (X VARCHAR2(10 BYTE), Y VARCHAR2(80 CHAR), Z VARCHAR2(30 BYTE));

Пожалуйста, проверьте ваш скрипт тщательно, попросите кого-нибудь еще просмотреть скрипт и создать резервную копию базы данных перед его запуском. :

CREATE OR REPLACE PROCEDURE p AS
BEGIN
  FOR r IN (
     SELECT 'UPDATE ' || table_name ||' SET ' || 
            LISTAGG(column_name||'=RTRIM('||column_name||')', ', ')
            WITHIN GROUP (ORDER BY column_id) as stmt
       FROM user_tab_columns
      WHERE data_type='CHAR'
      GROUP BY table_name
      ORDER BY table_name)
  LOOP
    DBMS_OUTPUT.PUT_LINE(r.stmt);
    EXECUTE IMMEDIATE r.stmt;
    COMMIT;
  END LOOP;

  FOR r IN (
     SELECT 'ALTER TABLE '||table_name||' MODIFY ('||LISTAGG(
             column_name||
           ' VARCHAR2('||data_length||' '||DECODE(char_used,'B','BYTE','C','CHAR')||')', ', ') 
             WITHIN GROUP (ORDER BY column_id) ||')' as stmt
       FROM user_tab_columns
      WHERE data_type='CHAR'
      GROUP BY table_name
     ORDER BY table_name)
  LOOP
    DBMS_OUTPUT.PUT_LINE(r.stmt);
    EXECUTE IMMEDIATE r.stmt;
  END LOOP;
END p;
/

РЕДАКТИРОВАТЬ:

РЕДАКТИРОВАТЬ:

О, я забыл, вы можете реорганизовать таблицы, чтобы освободившееся свободное пространство снова стало доступным. Минимальный пример:

CREATE TABLE t (c CHAR(2000));
CREATE INDEX i ON t(c);
INSERT INTO t SELECT 'x' FROM all_objects;
67,114 rows inserted.

Размер таблицы 184 МБ, индекс 240 МБ:

SELECT segment_type, segment_name, round(bytes/1024/1024) AS mb 
  FROM user_segments WHERE segment_name IN ('T','I');

INDEX I 240
TABLE T 184

Теперь, если вы конвертируете и обрезаете таблицу, таблица и индекс по-прежнему остаются тот же размер:

ALTER TABLE t MODIFY (c VARCHAR2(2000));
UPDATE t SET c = RTRIM(c);

INDEX I 240
TABLE T 184

Только после реорганизации таблицы Oracle избавляется от пробелов, которые больше не нужны. Таблица теперь 1 МБ, индекс 2 МБ:

ALTER TABLE t MOVE;
ALTER INDEX I REBUILD;

INDEX I 2
TABLE T 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...