无法通过XML查询多个表:XML处理中发生错误

时间:2018-12-10 14:56:57

标签: sql oracle dbms-xmlgen

我想从column_name中获得一个table_nameall_tab_columns的列表(直到这里都没有问题),并且也想为每个给定的列都转到原始表格/列,然后查看发生率最高的最高值是什么。

在下面的查询中,我获得了1个表中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

我举一个例子。例如,这是我的两个表; 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  

如此

  • 从T1 / Col.1中我应该得到'y'
  • 从T1 / col.3中我应该得到'm2'
  • 从T2 / col.3中我应该得到'xxx'

以此类推。

1 个答案:

答案 0 :(得分:1)

报告给您的重要错误是这个:

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

XMLQuery返回XMLtype结果,您的客户端显然将其显示为(XMLTYPE)。您可能可以更改该行为-例如在Sql Developer中从工具->首选项->数据库->高级-> DIsplay XMl值在网格中。但是,您也可以将结果转换为字符串,使用getStringVal()返回varchar2(如果具有CLOB值,则返回getClobVal(),这可能会导致其他问题):

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子句中指定如何决定打破平局。

  

我实际上想查看所有结果,但是我希望能在不同的行中看到它们

允许使用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交叉连接到XMLTable,该表执行更简单的dbms_xmlgen.get_xml()调用以仅获取每个值及其计数,从生成的XML中提取值和计数作为关系数据,并且包括排名功能作为该子查询的一部分,而不是XML生成之内。如果您单独运行子查询,则会看到所有possibel值及其计数以及每个值的排名。

外部查询仅对排名进行过滤,并向您显示子查询中排名第一的相关列。

db<>fiddle