Sql 如何使用数据更改列的数据类型

Sql 如何使用数据更改列的数据类型,sql,oracle,Sql,Oracle,假设我有一个表call\u log,其中有一列名为duration。让我们进一步假设,当我将表放在一起时,我犯了一个错误,将duration设置为varchar列而不是数字。现在我无法对该列进行正确排序。我想重命名该列,以便发布 ALTER TABLE call_log MODIFY (duration NUMBER); 但是我得到 ORA-01439: column to be modified must be empty to change datatype. 我的表已被使用,并且有数据

假设我有一个表
call\u log
,其中有一列名为
duration
。让我们进一步假设,当我将表放在一起时,我犯了一个错误,将
duration
设置为varchar列而不是数字。现在我无法对该列进行正确排序。我想重命名该列,以便发布

ALTER TABLE call_log MODIFY (duration NUMBER);
但是我得到

ORA-01439: column to be modified must be empty to change datatype.

我的表已被使用,并且有数据!我不想丢失数据。如何修改列的数据类型而不丢失数据?

使用正确的数据类型创建临时列,将数据复制到新列,删除旧列,重命名新列以匹配旧列的名称

ALTER TABLE call_log ADD (duration_temp NUMBER);
UPDATE call_log SET duration_temp = duration;
ALTER TABLE call_log DROP COLUMN duration;
ALTER TABLE call_log RENAME COLUMN duration_temp TO duration;

这个答案的想法来源于。

前面的解决方案非常好,但是如果您不想更改call_log table结构中的列顺序,则以下步骤适用于此:

create table temp_call_log  as select * from call_log; /* temp backup table for call_log */
UPDATE call_log SET duration = null;
/*check,... be sure.... then commit*/
commit;
ALTER TABLE call_log MODIFY duration NUMBER;
UPDATE call_log c SET c.duration = (select t.duration from temp_call_log t where t.primarykey_comumn = c.primarykey_column);
/*check,... be sure.... then commit*/
commit;
drop table temp_call_log;
注1:在表调用日志中将主键更改为主键


注2:此解决方案假设您的数据大小不大。

或者一些限制,我无法使用前两种解决方案:

CREATE TABLE call_log_temp AS (SELECT * FROM call_log where rownum = 0);
ALTER TABLE call_log_temp MODIFY duration NUMBER;
INSERT INTO call_log_temp( id, duration, and_all_other_columns, ... )
  SELECT id, duration, and_all_other_columns, ...
  FROM call_log;  
DROP TABLE call_log;    
ALTER TABLE call_log_temp RENAME TO call_log;

保留原始列顺序的最佳解决方案:创建临时列,将数据复制到临时列,将原始列设置为null,修改其类型,将临时列中的数据设置回临时列,然后删除临时列:

ALTER TABLE call_log ADD duration_temp NUMBER;
UPDATE call_log SET duration_temp = duration;
UPDATE call_log SET duration = NULL;
ALTER TABLE call_log MODIFY duration NUMBER;
UPDATE call_log SET duration = duration_temp;
ALTER TABLE call_log DROP (duration_temp);

请对评论投赞成票。我一次性执行了上一个解决方案,但由于某些原因,它没有按预期工作。我丢失了该列的所有信息,无法回滚。下次我肯定会逐行执行并检查以确保。。。