使用动态SQL

时间:2016-08-18 16:01:44

标签: sql oracle database-migration sqldatatypes

我正在迁移数据库,并且正在尝试将表结构信息检索到单个行项目中以进行机器处理。由于技术原因,不能使用现有的迁移工具,必须以这种方式处理它。

我在多个表上成功运行了以下查询:

SELECT LISTAGG(column_name || ',' || data_type || ',' || data_length, ',')
WITHIN GROUP (ORDER BY column_id)
FROM all_tab_cols
WHERE table_name = 'MyTableName'

对于许多表格而言,它可以正常工作并且完全按照我的期望返回:

ColumnName1, VARCHAR2, 20, ColumnName2, NUMBER, 22, ColumnName3, CHAR, 3, ...

然而,有时它并不完全正确。例如,我从DB设计文档中知道ColumnName2应该是长度为2的数字,而不是22.为什么返回错误?

更令人费解的是,有时根本不起作用而且什么都不返回。我当时认为这是导致问题的CHAR数据类型,但我的一些表有CHAR工作正常。如果它们是INTEGER,SHORTINT或DATE类型,它似乎总是给我带来问题。解决这个问题的最佳方法是什么?

我也知道该表存在,因为当我运行一个简单的

SELECT * FROM MyTableName

它返回表中的所有记录。

更新

我尝试用data_precision替换data_length,对于数字,它返回了正确的答案,但现在我没有任何VARCHAR2。我如何重构我的查询以获取data_precision,如果它是一个数字,而不是给我data_length如果它是什么?

另外,我还有几张桌子不允许我查看他们的结构。我对模式仍然不太熟悉,但我理解有时候一个表可能存在于不同的表下。但是为什么用SELECT *返回数据,但是当我查看all_tab_col时,这里的结构信息不会出现?

1 个答案:

答案 0 :(得分:2)

您需要根据data_length决定是否使用data_precisiondata_type,您可以使用案例表达式执行此操作:

select listagg(column_name ||','|| data_type ||','||
  case 
    when data_type in ('VARCHAR2', 'NVARCHAR2', 'CHAR', 'RAW')
      then to_char(data_length)
    when data_type = 'NUMBER'
        and (data_precision is not null or data_scale is not null)
      then data_precision || case
        when data_scale > 0 then '.' || data_scale
      end
    end, ',') within group (order by column_id)
from all_tab_columns
where table_name = 'MYTABLENAME'
and owner = user -- if it is always current user, use user_tab_columns instead
/

如果我将该表创建为:

create table mytablename (col1 varchar2(20), col2 number(2), col3 char(3), col4 date,
  col5 timestamp(3), col6 clob, col7 number(5,2));

然后该查询产生:

COL1,VARCHAR2,20,COL2,NUMBER,2,COL3,CHAR,3,COL4,DATE,,COL5,TIMESTAMP(3),,COL6,CLOB,,COL7,NUMBER,5.2

在此示例中,我将数字表示为精度比例,但您可能没有担心的比例,或者可能想要以不同的方式处理它们 - 取决于结果的使用方式。我已经为没有大小的数据类型添加了一个空字段,例如CLOB和DATE。

另请注意,时间戳(和时间间隔)包括数据类型本身的精度,因此timestamp(3)直接来自该列的data_type。带有时区和时间间隔的时间戳也包括数据类型名称中的空格。

所以这是一个起点,您可以将它扩展到您需要以特定方式处理的其他数据类型,或者(比方说)将时间戳精度分成单独的逗号分隔字段。