代码之家  ›  专栏  ›  技术社区  ›  Jay Askren

如何使用jdbc从Oracle中的resultset获取模式名?

  •  3
  • Jay Askren  · 技术社区  · 14 年前

    我想在Oracle数据库上运行一个查询,对于结果集中的每一列,我想知道该列来自哪个模式。我尝试了以下方法:

    ResultSetMetaData rsMetadata = rs.getMetaData();
    String schemaName = rsMetadata.getSchemaName(1)
    

    但是,这将返回空字符串。是否有办法获取架构名称?

    编辑以响应OMG小马:

    我们正在开发的工具从数据库中获取数据,并对数据进行分析,以找到给定问题的信息量最大的子集。然后我们创建一个查询,该查询只返回针对给定问题提供信息的行。例如,如果我们有一个客户数据库,想知道哪些客户最有可能停止他们的服务,我们的工具可以创建一个查询,返回5%的客户记录,然后可以通过高性能的分析算法运行。这样做的好处是,我们只对数据的一个子集进行分析,这当然会节省时间。事实证明,高性能的分析算法现在工作得更好,因为第一步基本上是从我们的数据中过滤噪声。

    SELECT* FROM bar.customer;
    

    如果由于某种原因,眼睛颜色和性别是人们停止服务的预测因素,那么我们的系统生成的查询可能如下所示:

    SELECT * FROM bar.customer WHERE bar.customer.eye_color='blue' 
                                     AND bar.customer.gender='M' 
    

    最好知道结果集中每个列的模式,这样我们就可以确保查询正确运行。我们可以假设该模式与数据库连接中使用的模式相同,并且在99%的情况下应该是正确的。我只是担心有1%的时间用户可能会做一些意想不到的事情,比如对另一个模式运行查询。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Alex Poole    14 年前

    据一位老先知说 code sample :

    OracleResultSetMetaData接口没有实现getSchemaName()和getTableName()方法,因为底层协议不允许这样做。

    对我来说意味着 ResultSetMetaData

    有一个网络逻辑8 document 这表明这是可以做到的,但在以后的版本中,类型4驱动程序已被弃用。所以你还是有可能找到一个支持 getSchemaName() 反对甲骨文,但似乎不太可能。

        2
  •  0
  •   Jon Heller TenG    14 年前

    --#1: Create some test data
    create table employee (id number primary key, name varchar2(100), department_id number);
    create table department(id number primary key, name varchar2(100), test number);
    insert into department select level, 'department test', level from dual connect by level <= 100;
    insert into employee select level, 'employee test', level from dual connect by level <= 100;
    
    --Actually run the query for this example so there will be data in the data dictionary.
    select employee.* from employee inner join department on department_id = department.id;
    
    --#2: The first difficult part is to find the sql_id of the query.  Can you get this directly from the
    --    result set?  If not not you'll have to find it.
    --    I'm not exactly sure how you'll want to do this, here are some options:
    --Look at the last loaded query in v$sql (I don't think this always works, especially if the query has run multiple times)
    select * from v$sql where v$sql.parsing_schema_name = user order by first_load_time desc;
    --Compare the query text (sql_text removes newlines, sql_fulltext is a clob)
    select * from v$sql where sql_text like 'select employee.* from employee inner join department on department_id = department.id%';
    --Find the last sql_id for this session.  This doesn't work for me, maybe it's just an express edition bug?
    select prev_sql_id, v$session.* from v$session where sid = sys_context('USERENV', 'SID');
    
    --Look at the plan.  Note that there may be an index instead of a table.
    --(On my system the sql_id is 0k2t2y1d312j8, but it will probably be different on yours)
    select * from v$sql_plan where sql_id = '0k2t2y1d312j8';
    
    --3: Create a type and a function to return all of the columns from a specific query.
    --It'd be more consistent to use the SQL_ID here, but then there are permission issues if we
    --have to get the text from v$sql.
    
    create or replace type varchar2_tab is table of varchar2(30);
    /
    
    create or replace function get_columns(sql_text in varchar2) return varchar2_tab
    authid current_user pipelined is
      my_cursor    number;
      column_count number;
      my_columns   DBMS_SQL.DESC_TAB;
    begin
      select count(*) into column_count from v$sql;
      my_cursor := dbms_sql.open_cursor;
      dbms_sql.parse(my_cursor, sql_text, dbms_sql.native); 
      dbms_sql.describe_columns(my_cursor, column_count, my_columns);
      for i in 1 .. my_columns.count loop
        pipe row(my_columns(i).col_name);
      end loop;
      dbms_sql.close_cursor(my_cursor);
    end;
    /
    
    --Test queries.  Note that it's possible for a column to be listed twice.
    select * from table(get_columns('select employee.* from employee inner join department on department_id = department.id'));
    
    --4: Find the columns and their tables and schemas that are used in a query.
    --Currently this only works for tables and indexes in the explain plan.
    --There's probably a large number of items that won't work - materialized views, clusters(?), pipelined functiions, etc.
    --You'll need to add each object type as necessary.
    --(Remember to replace the SQL_ID and the query text with the real values)
    select distinct owner, table_name, column_name
    from
    (
      --Find all the columns for the relevant tables
      select all_tab_cols.owner, all_tab_cols.table_name, all_tab_cols.column_name
      from
      (
        --Find the relevant tables from the plans (may need to find the table behind an index)
        select
          nvl(all_indexes.table_owner, plan_objects.object_owner) owner,
          nvl(all_indexes.table_name, plan_objects.object_name) table_name
        from
        (
          select object_owner, object_name, object_type
          from v$sql_plan
          where sql_id = '0k2t2y1d312j8'
            and
            (
              object_type = 'TABLE'
              or object_type like 'INDEX%'
            )
        ) plan_objects
        left outer join all_indexes
          on plan_objects.object_name = all_indexes.index_name
            and plan_objects.object_type like 'INDEX%'
      ) relevant_tables
      inner join all_tab_cols
        on relevant_tables.owner = all_tab_cols.owner
          and relevant_tables.table_name = all_tab_cols.table_name
    ) relevant_tab_cols
    --It would be more 
    inner join table(get_columns('select employee.* from employee inner join department on department_id = department.id')) all_possible_columns
      on relevant_tab_cols.column_name = all_possible_columns.column_value;