【问题标题】:Retrieving Table Structure with Dynamic SQL使用动态 SQL 检索表结构
【发布时间】:2016-12-25 15:45:29
【问题描述】:

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

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

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时却没有这里的结构信息呢?

【问题讨论】:

  • 您应该小心 ALL_TAB_COLS 上的 OWNER。此外,在数字上,您应该使用 DATA_PRECISION 和 DATA_SCALE 而不是 DATA_LENGTH
  • @Vercelli 这三个有什么区别?我对 SQL 还是比较陌生... OWNER 有什么问题?我没有在这个数据库中写任何东西,只是从中读取。
  • 我会尝试解析select dbms_metadata.get_ddl('TABLE','MYTABLENAME', 'MYSCHEMA') FROM DUAL的结果
  • 查看 all_tab_cols 视图的定义:docs.oracle.com/cd/B19306_01/server.102/b14237/…
  • @SandPiper - 您可以使用大小写表达式;您所做的与this describe alternative 非常相似,尽管您可能必须扩展该概念以处理更多数据类型。您的预期输出似乎是逗号分隔的列名、类型和大小/精度列表;您将如何处理具有比例和精度(两个值)的数字,以及没有大小限制的日期和 CLOB?

标签: sql oracle database-migration sqldatatypes


【解决方案1】:

你需要根据data_type来决定是使用data_length还是data_precision,你可以用一个case表达式来做到这一点:

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

在此示例中,我将数字表示为 precision.scale,但您可能无需担心比例尺,或者可能希望以不同方式处理它们 - 取决于结果将如何使用。我为没有大小的数据类型添加了一个空字段,例如CLOB 和 DATE。

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

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

【讨论】:

  • 这个概念效果很好。我修改了最后一个case语句,所以如果data_scale = 0它返回'Integer',如果它>0它返回'Double'。非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 2020-03-11
  • 1970-01-01
相关资源
最近更新 更多