【问题标题】:How do I get column datatype in Oracle with PL-SQL with low privileges?如何使用低权限的 PL-SQL 在 Oracle 中获取列数据类型?
【发布时间】:2011-01-21 07:06:18
【问题描述】:

我对 Oracle 数据库中的一些表具有“只读”权限。我需要获取有关某些列的架构信息。我想使用类似于 MS SQL 的sp_help 的东西。

我看到此查询中列出了我感兴趣的表:

SELECT * FROM ALL_TABLES

当我运行这个查询时,Oracle 告诉我“在模式中找不到表”,是的,参数是正确的。

SELECT 
DBMS_METADATA.GET_DDL('TABLE', 'ITEM_COMMIT_AGG', 'INTAMPS') AS DDL
FROM DUAL;

使用我的 Oracle 通用翻译器 9000 后,我推测这不起作用,因为我没有足够的权限。考虑到我的限制,我如何才能通过 PL-SQL 语句获取我可以读取的表上列的数据类型和数据长度?

【问题讨论】:

    标签: oracle plsql ddl privileges


    【解决方案1】:
    DECLARE
      c           NUMBER;
      d           NUMBER;
      col_cnt     INTEGER;
      f           BOOLEAN;
      rec_tab     DBMS_SQL.DESC_TAB;
      col_num    NUMBER;
    
      PROCEDURE print_rec(rec in DBMS_SQL.DESC_REC) IS
      BEGIN
        DBMS_OUTPUT.NEW_LINE;
        DBMS_OUTPUT.PUT_LINE('col_type            =    '
                             || rec.col_type);
        DBMS_OUTPUT.PUT_LINE('col_maxlen          =    '
                             || rec.col_max_len);
        DBMS_OUTPUT.PUT_LINE('col_name            =    '
                             || rec.col_name);
        DBMS_OUTPUT.PUT_LINE('col_name_len        =    '
                             || rec.col_name_len);
        DBMS_OUTPUT.PUT_LINE('col_schema_name     =    '
                             || rec.col_schema_name);
        DBMS_OUTPUT.PUT_LINE('col_schema_name_len =    '
                             || rec.col_schema_name_len);
        DBMS_OUTPUT.PUT_LINE('col_precision       =    '
                             || rec.col_precision);
        DBMS_OUTPUT.PUT_LINE('col_scale           =    '
                             || rec.col_scale);
        DBMS_OUTPUT.PUT('col_null_ok         =    ');
        IF (rec.col_null_ok) THEN
          DBMS_OUTPUT.PUT_LINE('true');
        ELSE
          DBMS_OUTPUT.PUT_LINE('false');
        END IF;
      END;
    BEGIN
      c := DBMS_SQL.OPEN_CURSOR;
    
    -- YOUR SELECT HERE
      DBMS_SQL.PARSE(c, '
    
    SELECT *
    FROM table1 a
         bable2 b
         table3 c
    where a.id = b.id
      and b.id2 = c.id
    
      ', DBMS_SQL.NATIVE);
    
      d := DBMS_SQL.EXECUTE(c);
    
      DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
    
      col_num := rec_tab.first;
      IF (col_num IS NOT NULL) THEN
        LOOP
          print_rec(rec_tab(col_num));
          col_num := rec_tab.next(col_num);
          EXIT WHEN (col_num IS NULL);
        END LOOP;
      END IF;
    
      DBMS_SQL.CLOSE_CURSOR(c);
    END;
    /
    

    【讨论】:

      【解决方案2】:

      要查看以字节为单位的内部表示大小,您可以使用:

      REGEXP_SUBSTR(DUMP(your_column_name), 'Len=(\d+)\:', 1, 1, 'c', 1 ) 
      

      【讨论】:

        【解决方案3】:

        你可以试试这个。

        SELECT *
          FROM (SELECT column_name,
                       data_type,
                       data_type
                       || CASE
                             WHEN data_precision IS NOT NULL
                                  AND NVL (data_scale, 0) > 0
                             THEN
                                '(' || data_precision || ',' || data_scale || ')'
                             WHEN data_precision IS NOT NULL
                                  AND NVL (data_scale, 0) = 0
                             THEN
                                '(' || data_precision || ')'
                             WHEN data_precision IS NULL AND data_scale IS NOT NULL
                             THEN
                                '(*,' || data_scale || ')'
                             WHEN char_length > 0
                             THEN
                                '(' || char_length
                                || CASE char_used
                                      WHEN 'B' THEN ' Byte'
                                      WHEN 'C' THEN ' Char'
                                      ELSE NULL
                                   END
                                || ')'
                          END
                       || DECODE (nullable, 'N', ' NOT NULL')
                          DataTypeWithLength
                  FROM user_tab_columns
                 WHERE table_name = 'CONTRACT')
         WHERE DataTypeWithLength = 'CHAR(1 Byte)';
        

        【讨论】:

        • 欢迎来到stackoverflow。除了您的代码之外,最好还添加一个简短的文本,说明您的答案为何正确,并为 OP 输入以纠正他们面临的任何错误。
        【解决方案4】:

        快速而肮脏的方式(例如查看数据在 oracle 中的存储方式)

        SQL> select dump(dummy) dump_dummy, dummy
             , dump(10) dump_ten
        from dual
        
        DUMP_DUMMY       DUMMY DUMP_TEN            
        ---------------- ----- --------------------
        Typ=1 Len=1: 88  X     Typ=2 Len=2: 193,11 
        1 row selected.
        

        将显示表 sys.dual 中的虚拟列具有 typ=1 (varchar2),而 10 是 Typ=2(数字)。

        【讨论】:

          【解决方案5】:

          Oracle:获取表中完整数据类型的列表:

          select data_type || '(' || data_length || ')' 
          from user_tab_columns where TABLE_NAME = 'YourTableName'
          

          【讨论】:

            【解决方案6】:
            select column_name, data_type || '(' || data_length || ')' as datatype
            from all_tab_columns 
            where TABLE_NAME = upper('myTableName')
            

            【讨论】:

              【解决方案7】:
              select t.data_type 
                from user_tab_columns t 
               where t.TABLE_NAME = 'xxx' 
                 and t.COLUMN_NAME='aaa'
              

              【讨论】:

              • 很好,对于当前架构之外的表user_tab_columns 可以替换为all_tab_columns
              【解决方案8】:

              我为这种情况找到的最佳解决方案是

              select column_name, data_type||
              case
              when data_precision is not null and nvl(data_scale,0)>0 then '('||data_precision||','||data_scale||')'
              when data_precision is not null and nvl(data_scale,0)=0 then '('||data_precision||')'
              when data_precision is null and data_scale is not null then '(*,'||data_scale||')'
              when char_length>0 then '('||char_length|| case char_used 
                                                                       when 'B' then ' Byte'
                                                                       when 'C' then ' Char'
                                                                       else null 
                                                         end||')'
              end||decode(nullable, 'N', ' NOT NULL')
              from user_tab_columns
              where table_name = 'TABLE_NAME'
              and column_name = 'COLUMN_NAME';
              

              @Aaron Stainback,感谢您的指正!

              【讨论】:

              • 您需要添加 CHAR_USED 以便您可以判断它是在 varchar2 之类的东西中定义为字节还是字符
              • 这是很好的代码,但如果是 INT 字段,它会返回“NUMBER(*,0)” 它需要一些更正
              • @FirasNizam 试试看 - 也许我没有正确理解你,但是当 data_scale 为 0 时它返回 NUMBER(),当它是 != 0 时它返回 NUMBER( ,data_scale)
              • 这完全是我所搜索的。案例中的分离对于获得正确的类型定义非常重要。谢谢你!
              【解决方案9】:

              ALL_TAB_COLUMNS 应该可以从 PL/SQL 查询。 DESC 是一个 SQL*Plus 命令。

              SQL> desc all_tab_columns;
               Name                                      Null?    Type
               ----------------------------------------- -------- ----------------------------
               OWNER                                     NOT NULL VARCHAR2(30)
               TABLE_NAME                                NOT NULL VARCHAR2(30)
               COLUMN_NAME                               NOT NULL VARCHAR2(30)
               DATA_TYPE                                          VARCHAR2(106)
               DATA_TYPE_MOD                                      VARCHAR2(3)
               DATA_TYPE_OWNER                                    VARCHAR2(30)
               DATA_LENGTH                               NOT NULL NUMBER
               DATA_PRECISION                                     NUMBER
               DATA_SCALE                                         NUMBER
               NULLABLE                                           VARCHAR2(1)
               COLUMN_ID                                          NUMBER
               DEFAULT_LENGTH                                     NUMBER
               DATA_DEFAULT                                       LONG
               NUM_DISTINCT                                       NUMBER
               LOW_VALUE                                          RAW(32)
               HIGH_VALUE                                         RAW(32)
               DENSITY                                            NUMBER
               NUM_NULLS                                          NUMBER
               NUM_BUCKETS                                        NUMBER
               LAST_ANALYZED                                      DATE
               SAMPLE_SIZE                                        NUMBER
               CHARACTER_SET_NAME                                 VARCHAR2(44)
               CHAR_COL_DECL_LENGTH                               NUMBER
               GLOBAL_STATS                                       VARCHAR2(3)
               USER_STATS                                         VARCHAR2(3)
               AVG_COL_LEN                                        NUMBER
               CHAR_LENGTH                                        NUMBER
               CHAR_USED                                          VARCHAR2(1)
               V80_FMT_IMAGE                                      VARCHAR2(3)
               DATA_UPGRADED                                      VARCHAR2(3)
               HISTOGRAM                                          VARCHAR2(15)
              

              【讨论】:

              • @leanne 你这样使用这个表:SELECT * FROM user_tab_columns WHERE table_name = 'FILL_IN_THE_TABLE_NAME' AND column_name = 'FILL_IN_THE_COLUMN_NAME';
              • 是的,@Tenzin - 几年前这里提供了多个示例,例如您的示例,包括对这篇文章的编辑。如果您单击此答案中的“已编辑 ...”行,您将看到亚当添加的内容以更好地解释。 (谢谢,亚当!)
              【解决方案10】:

              注意:如果您尝试获取位于不同 SCHEMA 中的表的此信息,请使用 all_tab_columns 视图,我们会遇到此问题,因为我们的应用程序出于安全目的使用不同的 SCHEMA。

              使用以下内容:

              EG:

              SELECT
                  data_length 
              FROM
                  all_tab_columns 
              WHERE
                  upper(table_name) = 'MY_TABLE_NAME' AND upper(column_name) = 'MY_COL_NAME'
              

              【讨论】:

              • data_length 根本不重要。正确的长度定义是用精度和比例定义的。
              【解决方案11】:

              您可以使用desc 命令。

              desc MY_TABLE
              

              这将为您提供列名、null 是否有效以及数据类型(如果适用,还有长度)

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-01-05
                • 2013-11-05
                • 2021-11-24
                • 2020-05-29
                • 1970-01-01
                • 1970-01-01
                • 2010-09-27
                • 1970-01-01
                相关资源
                最近更新 更多