在 Oracle 中更新表
Posted
技术标签:
【中文标题】在 Oracle 中更新表【英文标题】:Update a table in Oracle 【发布时间】:2020-05-05 23:08:22 【问题描述】:我需要将 CHAR 类型的表的列更改为 VARCHAR2,但他们要求我自动执行此操作,因为它们是 100 个表。的所有列而不需要逐列放置的一种方法是使用从 user_tables 的视图中提取列的方法,但是这些表在执行数据时具有数据,将 CHAR 处理的空格更改为权利也传递给 VARCHAR2 我需要的是更新应用 RTRIM 的表的数据,我用更新表 set column = rtrim (column);但他们问我更新不是逐列而是在整个表中,所以它只是一个查询,有没有办法实现它?我用谷歌搜索,只找到我已经使用的语法
【问题讨论】:
【参考方案1】:您可以使用 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));
请彻底测试您的脚本,让其他人查看脚本并在运行之前备份数据库。
编辑:
您可以将语句包装在 PL/SQL 过程中:
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 MB,索引240 MB:
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
现在,如果你转换和 rtrim 表格,表格和索引仍然是相同的大小:
ALTER TABLE t MODIFY (c VARCHAR2(2000));
UPDATE t SET c = RTRIM(c);
INDEX I 240
TABLE T 184
只有在重新组织表之后,Oracle 才会删除不再需要的空间。该表现在为 1 MB,索引为 2 MB:
ALTER TABLE t MOVE;
ALTER INDEX I REBUILD;
INDEX I 2
TABLE T 1
【讨论】:
谢谢,您的回答对我很有帮助,您知道我是否可以在 PL/SQL 中执行此操作吗? 当然。就个人而言,我不会对此感到满意,我宁愿生成一个带有语句的 SQL 脚本,我会在测试数据库中对其进行双重检查和测试。但为了示例,我将编辑我的答案。 您是否提到“想要重新排列表格以便释放的空白再次可用”是通过什么方式完成的?以上是关于在 Oracle 中更新表的主要内容,如果未能解决你的问题,请参考以下文章