Невозможно запросить несколько таблиц через XML: при обработке XML произошла ошибка - PullRequest
0 голосов
/ 10 декабря 2018

Я хотел бы получить column_name и table_name для списка из all_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 голосов
/ 10 декабря 2018

Важная ошибка в том, что вам сообщили, это:

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 возвращает результат типа XML, который ваш клиент, очевидно, показывает как (XMLTYPE).Вы, вероятно, можете изменить это поведение - например, в Sql Developer из Tool-> Preferences-> Database-> Advanced-> DIsplay XMl Value in Grid.Но вы также можете преобразовать результат в строку, используя getStringVal() для возврата 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" (ноль, 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.Если вы запустите подзапрос самостоятельно, вы увидите все возможные значения и их количество, а также ранжирование каждого значения.

Затем внешний запрос просто фильтрует ранжирование и показывает соответствующие столбцы изподзапрос для первого результата.

db <> fiddle

...