Динамическая табличная функция Oracle для использования в Tableau - PullRequest
2 голосов
/ 26 марта 2019

У нас большой объем данных на сервере Oracle 11g. Большинство инженеров используют Tableau для визуализации данных, но в настоящее время не существует отличного решения для визуализации прямо с сервера Oracle из-за структуры базы данных. К сожалению, это невозможно изменить, поскольку оно очень глубоко интегрировано с остальными нашими системами. Есть таблица «словарь», назовем ее tab_keys:

name  |   key
---------------
AB-7  |  19756
BG-0  |  76519
FY-10 |  79513
JB-2  |  18765
...
...

И есть также таблицы, фактически содержащие данные. Каждая запись в tab_keys имеет соответствующую таблицу данных, названную префиксом ключа с идентификатором, в этом случае мы будем использовать «dat_». Таким образом, AB-7 будет хранить все свои данные в таблице с именем dat_19756. Эти ключи не известны пользователю и используются только для отслеживания «за кадром». Пользователь знает только прозвище AB-7.

Tableau позволяет взаимодействовать с серверами Oracle с помощью стандартных операторов выбора SQL, но поскольку пользователь не знает значения ключа, он не может написать оператор SQL для запроса данных.

Tableau недавно добавила возможность пользователям запрашивать функции таблиц Oracle, поэтому я начал идти по пути написания табличной функции для запроса ключа и возврата таблицы результатов для использования в Tableau. Проблема состоит в том, что каждая таблица dat_ в основном уникальна с различным количеством столбцов, меток, количества записей и типов данных из следующей таблицы dat_.

Как правильно решить эту проблему? Могу ли я:

1) Написать функцию (какая таблица может вызывать inline в обычном SQL), чтобы возвращать объединенное имя таблицы, которое генерируется динамически? Я попробовал это:

create or replace FUNCTION TEST_FUNC 
(
  V_NAME IN VARCHAR2
) RETURN user_tables.table_name%type AS 
V_KEY VARCHAR(100);
V_TABLE user_tables.table_name%type;
BEGIN
  select KEY into V_KEY from my_schema.tab_keys where NAME = V_NAME;
  V_TABLE := dbms_assert.sql_object_name('my_schema.dat_' || V_KEY);
  RETURN V_TABLE;
END TEST_FUNC;

а затем SELECT * from TABLE(TEST_FUNC('AB-7')); но я получаю:

ORA-22905: cannot access rows from a non-nested table item
22905. 00000 -  "cannot access rows from a non-nested table item"
*Cause:    attempt to access rows of an item whose type is not known at
           parse time or that is not of a nested table type
*Action:   use CAST to cast the item to a nested table type

Я не мог придумать хороший способ ЗАКРЫТЬ таблицу как нужный мне тип таблицы. Можно ли это сделать в функции перед возвратом?

2) Написать табличную функцию? Якобы Tableau может запрашивать подобные таблицы, но затем я сталкиваюсь с проблемой динамической генерации типов (что, как я понимаю, нелегко), но с дополнительным усложнением необходимости одновременного использования несколькими пользователями, поэтому каждому пользователю потребуется Тип данных генерируется для них каждый раз, когда они подключаются к таблице (если я правильно понимаю).

Я должен думать, что мне не хватает чего-то простого. Как привести результат этого запроса к типу данных другой таблицы?

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Нет простого способа, чтобы одна универсальная функция возвращала динамически настраиваемую вложенную таблицу.С другими продуктами вы можете использовать Ref Cursor (который отображается на ODBC или объект JDBC ResultSet), но я понимаю, что Tableau не поддерживает эту опцию.

Одна вещь, которую вы можете сделать, - это генерировать представления из вашего словаря данных,Вы можете использовать этот запрос для создания одноразового скрипта.

select 'create or replace view "' || name || '" as select * from dat_' || key || ';'
from tab_keys;  

Двойные кавычки необходимы, потому что AB-7 не является допустимым именем объекта в Oracle из-за тире.

Это позволит вашим пользователям запрашивать свои данные следующим образом:

select * from "AB-7";

Обратите внимание, что им также придется использовать двойные кавычки.

Очевидно, что каждый раз, когда вы вставляете строку в tab_keys, вам необходимо создать требуемое представление.Это можно сделать через триггер.

0 голосов
/ 27 марта 2019

Вы можете построить динамический SQL в SQL с помощью программы с открытым исходным кодом Method4 :

select * from table(method4.dynamic_query(
    q'[
        select 'select *  from dat_'||key
        from tab_keys
        where name = 'AB-7'
    ]'
));

A
-
1

Программа объединяет интерфейс Oracle Data Cartridge с ANYDATASET для создания функции, которая может возвращать динамические типы.

Возможно, есть способ еще больше упростить интерфейс, но я еще не понял этого. Эти функции интерфейса Oracle Data Cartridge очень разборчивы и их нелегко упаковать.

Вот пример схемы, которую я использовал:

create table tab_keys(name varchar2(100), key varchar2(100));
insert into tab_keys
select 'AB-7' , '19756' from dual union all
select 'BG-0' , '76519' from dual union all
select 'FY-10', '79513' from dual union all
select 'JB-2' , '18765' from dual;

create table dat_19756 as select 1 a from dual;
create table dat_76519 as select 2 b from dual;
create table dat_79513 as select 3 c from dual;
create table dat_18765 as select 4 d from dual;
...