【问题标题】:Dynamic Oracle Table Function for use in Tableau用于 Tableau 的动态 Oracle 表函数
【发布时间】:2019-03-27 08:32:59
【问题描述】:

我们在 Oracle 11g 服务器中有大量数据。大多数工程师使用 Tableau 来可视化数据,但由于数据库的结构,目前还没有一个很好的解决方案可以直接从 Oracle 服务器进行可视化。不幸的是,这无法更改,因为它与我们的其他系统非常紧密地集成在一起。有一个“字典”表,我们称之为tab_keys

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

还有实际包含数据的表格。 tab_keys 中的每个条目都有一个对应的数据表,通过在 key 前面加上标识符来命名,在这种情况下,我们将使用“dat_”。因此 AB-7 会将其所有数据存储在一个名为 dat_19756 的表中。这些密钥不为用户所知,仅用于“幕后”跟踪。用户只知道 AB-7 的绰号。

Tableau 允许使用标准 SQL 选择语句与 Oracle 服务器通信,但由于用户不知道键值,他们无法编写 SQL 语句来查询数据。

Tableau 最近增加了用户查询 Oracle 表函数的能力,所以我开始写一个表函数来查询键,并返回一个结果表供 Tableau 使用。问题是每个 dat_ 表基本上是唯一的,具有不同数量的列、标签、记录数和来自下一个 dat_ 表的数据类型。

处理这个问题的正确方法是什么?我可以:

1) 编写一个函数(哪个 tableau 可以在常规 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 可以查询这些类似的表,但后来我遇到了动态生成类型的问题(我理解这并不容易),但是这增加了需要多个用户同时使用的复杂性,所以每个用户都需要一个每次连接到表时为他们生成的数据类型(如果我理解正确的话)。

我不得不认为我错过了一些简单的东西。如何将此查询的返回值转换为其他表的数据类型?

【问题讨论】:

  • user_tables.table_name%type 定义了一个与该列名称具有相同类型的变量,在本例中为 VARCHAR2(30)。不是与表格投影相匹配的记录;这将是user_tables%rowtype,但它是一个标量(不是多行集),无论如何是 SQL 不理解的 PL/SQL 构造。
  • 动态SQL怎么样?我不羡慕你在这里......

标签: sql oracle plsql tableau-api table-functions


【解决方案1】:

没有简单的方法可以让单个泛型函数返回动态可配置的嵌套表。对于其他产品,您可以使用 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 中插入一行时,您都需要创建所需的视图。这可以通过触发器来完成。

【讨论】:

  • 这可行。将数据添加到任何 dat_ 表时会怎样?是否需要再次运行脚本,或者视图是否已更新?
  • 视图基本上只是一个存储查询:当您从中选择时,视图会返回基础表中的任何数据。
  • 啊,我刚刚对此进行了测试,发现 Tableau 不允许您在自定义 sql 查询中参数化表名。这么近。
  • 这不是要求参数化的表名。这就是说您访问画面中的视图。视图看起来像简单的表格
  • 对,我想我应该说“Tableau 不允许您在 FROM 子句中参数化任何内容”,所以我不能将表或视图名称作为用户可以输入的参数。它必须在自定义 SQL 查询中显式。
【解决方案2】:

您可以使用开源程序Method4在SQL中构建动态SQL:

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

A
-
1

该程序将 Oracle Data Cartridge Interface 与ANYDATASET 结合起来,创建了一个可以返回动态类型的函数。

可能有一种方法可以进一步简化界面,但我还没有想出来。这些 Oracle Data Cartridge Interface 功能非常挑剔,不容易重新打包。

这是我使用的示例架构:

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;

【讨论】:

  • 这看起来很有希望。 Tableau 将如何利用这一点?我假设您将它安装在任何产生查询的系统上?
  • @HudsonMC 是的,该程序必须安装在 Oracle 数据库上。步骤列在存储库页面上,主要是下载程序并在 SQL*Plus 中运行@install
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 2020-07-19
  • 2013-03-24
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2015-09-02
  • 1970-01-01
相关资源
最近更新 更多