无法通过 XML 查询多个表:XML 处理时出错

Unable to query multiple tables via XML: Error occurred in XML processing

我想为来自 all_tab_columns 的列表获取 column_nametable_name(直到这里这不是问题)以及我想去的每个给定列到原始 table/column 并查看出现次数最多的最高值是什么。

通过下面的查询,我得到了 1 table:

中 1 个列示例的所需值
select   col1
from    (SELECT col1, rank () over (order by count(*) desc) as rnk
         from  T1
         Group by col1
         ) 
 where   rnk = 1

现在我想要这样的东西:

select  table_name,
        column_name,
        xmlquery('/ROWSET/ROW/C/text()'
            passing xmltype(dbms_xmlgen.getxml( 'select ' || column_name  || ' from (select ' || column_name ||', rank () over (order by count(*) desc) as rnk from ' 
            || table_name || ' Group by ' || column_name || ') where rnk = 1;'))
            returning content) as C
from all_tab_columns
where owner = 'S1'
and table_name in ('T1', 'T2', 'T3', 'T4')
;

但它不起作用。这是我得到的错误:

ORA-19202: Error occurred in XML processing
ORA-00933: SQL command not properly ended
ORA-06512: at "SYS.DBMS_XMLGEN", line 176
ORA-06512: at line 1
19202. 00000 -  "Error occurred in XML processing%s"
*Cause:    An error occurred when processing the XML function
*Action:   Check the given error message and fix the appropriate problem

我举个例子。例如,这是我的两个 table; T1:

col.1      col.2 col.3
----- ---------- -----
y                m1   
y             22 m2   
n             45 m2   
y             10 m5   

和 T2:

col.1 col.2   col.3
----- ------- -----
    1 germany xxx  
    2 england xxx  
    3 germany uzt  
    3 germany vvx  
    8 US      XXX  

所以

等等。

报告给您的重要错误是:

ORA-00933: SQL command not properly ended

dbms_xmlgen.getxml() 调用中的查询中删除分号:

select  table_name,
        column_name,
        xmlquery('/ROWSET/ROW/C/text()'
            passing xmltype(dbms_xmlgen.getxml( 'select ' || column_name  || ' from (select ' || column_name ||', rank () over (order by count(*) desc) as rnk from ' 
            || table_name || ' Group by ' || column_name || ') where rnk = 1'))
                                                                     -------^ no semicolon here
            returning content) as C
from all_tab_columns
...

你的 XPath 似乎也是错误的;您正在寻找 /ROWSET/ROW/C,但 C 是整个表达式的列别名,而不是正在计算的列。您需要在 查询中为列名 添加别名,并在 XPath 中使用它:

select  table_name,
        column_name,
        xmlquery('/ROWSET/ROW/COL/text()'
                           -- ^^^
            passing xmltype(dbms_xmlgen.getxml( 'select ' || column_name  || ' as col from (select ' || column_name ||', rank () over (order by count(*) desc) as rnk from ' 
                                                                            -- ^^^^^^
            || table_name || ' Group by ' || column_name || ') where rnk = 1'))
            returning content) as C
from all_tab_columns
... 

您的样本数据得到:

TABLE_NAME                     COLUMN_NAME                    C         
------------------------------ ------------------------------ ----------
T1                             col.1                          y         
T1                             col.2                          224510    
T1                             col.3                          m2        
T2                             col.1                          3         
T2                             col.2                          germany   
T2                             col.3                          xxx       

db<>fiddle

XML查询是 return 一个 XML 类型的结果,您的客户端显然显示为 (XMLTYPE)。你可能会改变这种行为 - 例如在 Sql 开发人员中,从工具->首选项->数据库->高级->DIsplay XMl 网格中的值。但是您也可以将结果转换为字符串,使用 getStringVal() 到 return a varchar2(或者 getClobVal() 如果您有 CLOB 值,这可能会导致其他问题):

select  table_name,
        column_name,
        xmlquery('/ROWSET/ROW/COL/text()'
            passing xmltype(dbms_xmlgen.getxml( 'select ' || column_name  || ' as col from (select ' || column_name ||', rank () over (order by count(*) desc) as rnk from ' 
            || table_name || ' Group by ' || column_name || ') where rnk = 1'))
            returning content).getStringVal() as C
                           -- ^^^^^^^^^^^^^^^
from all_tab_columns
... 

如您所见,当由于计数相等而出现联系时,这并没有达到您的预期 - 在您的示例中,发现 T1."col.2" 的不同值(null、10、22 , 45) 其中各出现一次;并且 XMLQuery 将它们全部放在一个结果中。您需要决定在这种情况下您希望发生什么;如果您只想看一个,那么您需要在分析 order by 子句中指定如何决定打破平局。

I actually want to see all results but I expected to see them in different rows

另一种方法是使用 XMLTable 而不是 XMLQuery:

select table_name, column_name, value
from (
  select atc.table_name, atc.column_name, x.value, x.value_count,
    rank() over (partition by atc.table_name, atc.column_name
      order by x.value_count desc) as rnk
  from all_tab_columns atc
  cross join xmltable(
    '/ROWSET/ROW'
    passing xmltype(dbms_xmlgen.getxml(
           'select "' || column_name  || '" as value, count(*) as value_count '
        || 'from ' || table_name || ' '
        || 'group by "' || column_name || '"'))
    columns value varchar2(4000) path 'VALUE',
            value_count number path 'VALUE_COUNT'
  ) x
  where atc.owner = user
  and atc.table_name in ('T1', 'T2', 'T3', 'T4')
)
where rnk = 1;

内部查询将 all_tab_columns 交叉连接到一个 XML 表,该表执行更简单的 dbms_xmlgen.get_xml() 调用以获取每个值及其计数,提取值并作为关系计数来自生成的 XML 的数据,并将排名函数作为该子查询的一部分,而不是在 XML 生成中。如果您 运行 子查询本身,您将看到所有可能的值及其计数,以及每个值的排名。

外部查询然后只过滤排名,并向您显示子查询中排名第一的结果的相关列。

db<>fiddle