【问题标题】:zero-length columns are not allowed - Creating a table from view不允许零长度列 - 从视图创建表
【发布时间】:2013-06-05 13:47:23
【问题描述】:

我设计了一个流程,将数据从视图复制到 oracle 中的相应表中。我所做的就是调用一个传递“视图名称”作为参数的过程,这会创建相应的表(如果不存在,则删除并创建表)。所以这是动态发生的,我有大约 50 个视图,它们被安排为 oracle 作业。

现在问题来了,我有一些表在某些日子里出现以下错误...

ORA-01723:不允许零长度列

我知道造成这种情况的原因是视图中的几列为空,但并非整天如此。是的,我应该对这些列使用 CAST,但是正如我提到的,这种情况是动态发生的,我不知道这些列是哪一列或那是哪个视图?在我开始创建表之前,任何可以确定视图中是否存在“零长度列”的线索,以便我可以想到一些解决方案。对此的任何更好的补救措施都非常感谢。

注意:

  1. CREATE TABLE TABLE_NAME AS SELECT * FROM VIEW_NAME --> 这是我的表创建 SQL。
  2. 我选择这个的原因是'INSERT INTO'可能会因为日志记录和锁定而花费更多的时间和资源。

谢谢, 娜迦'

【问题讨论】:

  • 为什么不使用物化视图?您对这些表的具体需求是什么?
  • 视图只是从单个表中筛选出来的简单选择,还是您将函数应用于值?

标签: oracle oracle11g database-administration


【解决方案1】:

正如您所说,您调用一个过程来从视图中创建一个表。所以我假设您已经在使用动态 SQL(Native Dynamic SQL aka EXECUTE IMMEDIATE 语句或 DBMS_SQL 包)来执行 DDL 语句。然后,您可以使用 Oracle 字典视图(例如 USER_VIEWSUSER_TAB_COLUMNS)生成更复杂的 CREATE TABLE AS 语句,以获取有关列的类型、长度、比例以及编写正确 CAST 调用可能需要的任何其他信息。

下面是一个肮脏的例子:

create or replace view v 
as 
  select decode(dummy, 'Y', '123') s 
       , 1 n
       , 2.2 f
       , cast (1.1 as number(5,3)) fs
    from dual
/

set serveroutput on
declare
  l_query varchar2(32767) := 'create table t as select <column list> from v';
  l_type varchar2(100);
begin
  for tc in (
    select * from user_tab_columns 
     where table_name = 'V'
     order by column_id
  ) loop
    l_type := tc.data_type;
    l_type := l_type || 
      case tc.data_type 
        when 'NUMBER' then 
          case when tc.data_precision is not null then '(' || tc.data_precision || case when tc.data_scale is not null then ','||tc.data_scale end || ')' end
        when 'VARCHAR2' then 
          '(' || tc.char_length || ' ' || case tc.char_used when 'C' then 'char' else 'byte' end || ')' 
       end;
    l_query := replace(l_query, '<column list>', 'cast("'||tc.column_name||'" as '|| l_type ||') "'||tc.column_name||'" ,<column list>');
  end loop;
  l_query := replace(l_query, ',<column list>');

  dbms_output.put_line(l_query);
end;
/

结果:

view V created.
anonymous block completed
create table t as select cast("S" as VARCHAR2(3 char)),cast("N" as NUMBER),cast("F" as NUMBER),cast("FS" as NUMBER(5,3)) from v

祝你好运。

【讨论】:

  • 好答案。我认为使用数据字典是做这件事的正确方法。但示例代码仅适用于原始数据类型,需要针对 timestamp 等类型进行扩展,并在任何其他情况下重现类型名称。
  • 非常感谢。我尝试了类似的方法并且它起作用了...创建视图 dummy_view 为 select 1 作为 id , null 作为 dept_no , 'naga' 作为名称 from dual; create table dummy_table as select * from dummy_view UNION ALL Select cast(null as number) , cast(null as varchar2(10)), cast(null as varchar2(10)) from dual where 1=2
  • 当然,代码是要展开的,只是一个例子来说明思路。
【解决方案2】:

我选择这个的原因是“INSERT INTO”可能会因为日志记录和锁定而花费更多的时间和资源。

我认为您每次删除和重新创建表格的方法都是基于错误的信念。截断它们并使用直接路径插入,可选地不记录,会给你几乎相同的结果而没有这个问题。如果您正在使用:

create table .. as select from ...

...那么无论如何您都在完全记录操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    • 2015-02-08
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 2020-09-04
    • 2017-04-10
    相关资源
    最近更新 更多