Вы можете использовать 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