【问题标题】:Select data from all tables which contain these data-column从包含这些数据列的所有表中选择数据
【发布时间】:2021-12-24 03:49:26
【问题描述】:

(我认为对于这里的大多数用户来说这可能是一个简单的问题..)

简短说明: 我需要一种方法(可能使用我不知道的 PL/SQL ..)来“从包含此类数据的所有表中选择定义的数据”

详细说明(示例): 我有不同数量的不同表。其中一个经常变化的部分——我不知道编号和名称——包含“FID”列。现在我需要两个步骤: a) 选择所有包含“FID”列的表。 (我知道如何一步一步做到这一点) b) 从所有找到的表中选择值 FID 并显示它。

对我来说,问题是从 a) 到 b) 的步骤。对于已知表,我会使用 UNION,但对于表的动态结果,我不知道..

【问题讨论】:

  • 那里可能有更好的答案,但在 plsql 中,您可以使用来自 a 的结果来组合动态 SQL(做一些循环以将您的联合选择构造为文本,然后将该文本作为动态 SQL 执行 -我不记得语法,但谷歌搜索会很快找到(只是一个快速的想法,因此评论而不是回答)

标签: oracle plsql oracle-sqldeveloper


【解决方案1】:

您可以使用an XML magic trick 的变体,通过使用dbms_xmlgen 根据对user_tab_columns 的查询将所有值放入XML 文档中:

select dbms_xmlgen.getxmltype(
       'select "' || column_name || '" from "' || table_name || '"')
from user_tab_columns
where upper(column_name) = 'FID'
and data_type = 'NUMBER';

... 我假设 FID 应该是数字 ID,因此仅限于数字列(并且还允许表和列名称的混合大小写/引号标识符,以防万一)。这为每个表提供了一行,其中一个 XML 文档列出了该表中的 FID 值。

然后,您可以从该 XML 中提取单个值,再次作为数字:

with cte (xml) as (
  select dbms_xmlgen.getxmltype(
         'select "' || column_name || '" as fid from "' || table_name || '"')
  from user_tab_columns
  where upper(column_name) = 'FID'
  and data_type = 'NUMBER'
)
select x.fid
from cte
cross apply xmltable(
  '/ROWSET/ROW'
  passing cte.xml
  columns fid number path 'FID'
) x;

或者,如果您想查看每个值来自的表/列,只需将它们包含在 CTE 中并选择列表:

with cte (table_name, column_name, xml) as (
  select table_name, column_name, dbms_xmlgen.getxmltype(
         'select "' || column_name || '" as fid from "' || table_name || '"')
  from user_tab_columns
  where upper(column_name) = 'FID'
  and data_type = 'NUMBER'
)
select cte.table_name, cte.column_name, x.fid
from cte
cross apply xmltable(
  '/ROWSET/ROW'
  passing cte.xml
  columns fid number path 'FID'
) x;

如果您想搜索其他架构,请改用all_tab_columns,并可选择包含每个表的所有者:

with cte (owner, table_name, column_name, xml) as (
  select owner, table_name, column_name, dbms_xmlgen.getxmltype(
         'select "' || column_name || '" as fid from "' || owner || '"."' || table_name || '"')
  from all_tab_columns
  where upper(column_name) = 'FID'
  and data_type = 'NUMBER'
)
select cte.owner, cte.table_name, cte.column_name, x.fid
from cte
cross apply xmltable(
  '/ROWSET/ROW'
  passing cte.xml
  columns fid number path 'FID'
) x;

db<>fiddle


这个技巧的基础可以追溯到to at least 2007,但可能更早,早于getxmltype() 存在(它似乎已在10g 中添加);我最初使用xmltype(getxml())

select xmltype(dbms_xmlgen.getxml(
       'select "' || column_name || '" from "' || table_name || '"'))
from user_tab_columns
where upper(column_name) = 'FID'
and data_type = 'NUMBER';

其中works most of the time,但如果任何表为空throws "ORA-06502: PL/SQL: numeric or value error"

【讨论】:

  • 看起来不错,谢谢。基本代码:SELECT XMLTYPE ( 创建错误:ORA-06502: PL/SQL: numeric or value error ORA-06512: at "SYS.XMLTYPE", line 272 ORA-06512: at line 1 06502. 00000 - "PL/ SQL:数字或值错误%s" *原因:发生算术、数字、字符串、转换或约束错误。....... *操作:更改数据、操作方式或声明方式这样值就不会违反约束。添加这有助于:WHERE ... AND TABLE_NAME LIKE 'H%';
  • @PierredelaVerre - 奇怪,可能是因为 XML 字符串太大,但 getxml() 返回一个 CLOB,xmltype() 应该处理它。但我添加了一个替代方案来避免这种转换——看看它是否会出现同样的错误会很有趣。
  • 奇怪:“select * from user_tab_columns where upper(column_name) = 'FID'”返回 70 行。您的简化语句有效,但返回 21 "NULL" 和 49 "(XMLTYPE)"
  • 哦,对了……我猜有 21 个带有 FID 的表是空的。这可以解释为什么它在第一个版本中出错。这并没有给出它所基于的计数版本,因为它仍然会返回零;或者在我之前使用过的数据版本中,我必须没有空表来处理。无论如何,更简单的版本更好。
  • 我用设置“Oracle 11g”测试了你的小提琴示例——它会产生错误。非常感谢您的帮助-目前我的 Oracle 似乎太旧了。祝你有美好的一天!
【解决方案2】:

如果你想使用 pl/sql 我真的很喜欢流水线函数:

create type result_type as Object ( text varchar2(2000) );

create type result_type_table as table of result_type;

create or replace function select_all( p_column_name in varchar2 )
return result_type_table
deterministic
pipelined
as
  v_table_name varchar2(40);
  v_result result_type := result_type('');
  v_table_name_cursor sys_refcursor;
  v_inner_cursor sys_refcursor;
begin
   open v_table_name_cursor
   for 'select a.table_name
        from user_tab_cols a
        ,    user_tables b
        where a.column_name = :1
        and   a.table_name = b.table_name'
   using upper(p_column_name);
   loop
      fetch v_table_name_cursor into v_table_name;
      exit when v_table_name_cursor%notfound;
      open v_inner_cursor
      for 'select '||p_column_name||' from '||v_table_name;
      loop   
         fetch v_inner_cursor into v_result.text; 
         exit when v_inner_cursor%notfound;
         pipe row (v_result );
      end loop;
      close v_inner_cursor;  
   end loop;
   close v_table_name_cursor;
end;
/

使用这个函数很简单:

select * from table( select_all('your_column_name') );

db<>fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 1970-01-01
    相关资源
    最近更新 更多