Важная ошибка в том, что вам сообщили, это:
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