从 Oracle/Mysql 中的通用数据创建 [物化] 视图

Posted

技术标签:

【中文标题】从 Oracle/Mysql 中的通用数据创建 [物化] 视图【英文标题】:Creating a [materialised]view from generic data in Oracle/Mysql 【发布时间】:2010-06-18 00:51:18 【问题描述】:

我有一个包含 3 个表的通用数据模型

CREATE TABLE Properties 
(
  propertyId int(11) NOT NULL AUTO_INCREMENT,
  name varchar(80) NOT NULL
)
CREATE TABLE Customers
(
  customerId int(11) NOT NULL AUTO_INCREMENT,
  customerName varchar(80) NOT NULL
)
CREATE TABLE PropertyValues
(
  propertyId int(11) NOT NULL,
  customerId int(11) NOT NULL,
  value varchar(80) NOT NULL
)
INSERT INTO Properties VALUES (1, 'Age');
INSERT INTO Properties VALUES (2, 'Weight');
INSERT INTO Customers VALUES (1, 'Bob');
INSERT INTO Customers VALUES (2, 'Tom');
INSERT INTO PropertyValues VALUES (1, 1, '34');
INSERT INTO PropertyValues VALUES (2, 1, '80KG');
INSERT INTO PropertyValues VALUES (1, 2, '24');
INSERT INTO PropertyValues VALUES (2, 2, '53KG');

我想做的是创建一个视图,该视图将属性中的所有行作为列,并将客户中的条目作为行。列值由 PropertyValues 填充。 例如

 customerId Age   Weight
 1          34    80KG
 2          24    53KG

我想我需要一个存储过程来执行此操作,也许还需要一个物化视图(“属性”表中的条目很少更改)。 有什么建议吗?

【问题讨论】:

【参考方案1】:

使用动态 SQL 生成视图很容易:

create or replace procedure gen_view
as
    cols_stmt varchar2(32767);
    from_stmt varchar2(32767);
    subq_name varchar2(30);
begin
    for r in ( select * from properties
               order by propertyid )
    loop
        subq_name := 'pv_'||trim(to_char(r.propertyid)); 
        cols_stmt := cols_stmt || ', '|| subq_name ||'.value as '||r.name;
        from_stmt := from_stmt || ' left join ( select value, customerid from propertyvalues where propertyid = '
            ||trim(to_char(r.propertyid))||') '||subq_name
            ||' on '||subq_name||'.customerid = customers.customerid';
    end loop;
    execute immediate 'create or replace view eav_view as select customers.customerid, customers.customername'
                        || cols_stmt
                        || ' from customers '
                        || from_stmt;
end gen_view;
/

这是它的工作原理:

SQL> exec gen_view

PL/SQL procedure successfully completed.

SQL> select * from eav_view
  2  /

CUSTOMERID
----------
CUSTOMERNAME
--------------------------------------------------------------------------------
AGE
--------------------------------------------------------------------------------
WEIGHT
--------------------------------------------------------------------------------
         1
Bob
34
80KG

         2
Tom
24
53KG


SQL>

让我们为一些客户创建一个新属性并为其插入值...

SQL> insert into properties values (3, 'FavouriteIceCream')
  2  /

1 row created.

SQL> insert into propertyvalues values (3, 1, 'Cherry Garcia')
  2  /

1 row created.

SQL> exec gen_view

PL/SQL procedure successfully completed.

SQL> select * from eav_view
  2  /

CUSTOMERID
----------
CUSTOMERNAME
--------------------------------------------------------------------------------
AGE
--------------------------------------------------------------------------------
WEIGHT
--------------------------------------------------------------------------------
FAVOURITEICECREAM
--------------------------------------------------------------------------------
         1
Bob
34
80KG
Cherry Garcia

         2
Tom
24
53KG

SQL>

“我想我需要一个存储的 执行此操作的程序,也许还有一个 物化视图(在 表“属性”很少更改)。”

问题是,属性 会发生变化,我猜你不会对何时发生这种情况进行监督。所以你会发现很难将更改应用到物化视图。这很重要,因为更改物化视图的投影需要删除它。因此,要在不中断服务的情况下做到这一点是非常困难的。类似的考虑适用于常规视图,但中断几乎为零。

如果您确实想将视图语句转换为物化视图,请注意 Oracle 在物化视图方面似乎不喜欢 ANSI-92 语法(它抛出 ORA-12054)。我不知道为什么会这样,但是当我改用旧的连接技术时问题就消失了,这很烦人,因为外部连接语法更笨拙。

无需重新创建数据库对象的解决方案是在返回映射到 JDBC ResultSet 的 Ref Cursor 的函数中使用动态 SQL:

create or replace function get_eav_view
    return sys_refcursor
as
    cols_stmt varchar2(32767);
    from_stmt varchar2(32767);
    subq_name varchar2(30);
    return_value sys_refcursor;
begin
    for r in ( select * from properties
               order by propertyid )
    loop
        subq_name := 'pv_'||trim(to_char(r.propertyid)); 
        cols_stmt := cols_stmt || ','|| subq_name ||'.value as '||r.name;
        from_stmt := from_stmt || ' left join ( select value, customerid from propertyvalues where propertyid = '
            ||trim(to_char(r.propertyid))||') '||subq_name
            ||' on '||subq_name||'.customerid = customers.customerid';
    end loop;
    open return_value for
            'select customers.customerid, customers.customername'
                    || cols_stmt
                    || ' from customers '
                    || from_stmt;
    return return_value;
end get_eav_view;
/

这将始终返回最新的投影:

SQL> var rc refcursor
SQL> exec :rc := get_eav_view

PL/SQL procedure successfully completed.

SQL> print rc

CUSTOMERID
----------
CUSTOMERNAME
--------------------------------------------------------------------------------
AGE
--------------------------------------------------------------------------------
WEIGHT
--------------------------------------------------------------------------------
FAVOURITEICECREAM
--------------------------------------------------------------------------------
         1
Bob
34
80KG
Cherry Garcia

         2
Tom
24
53KG


SQL>     

现在,如果我们添加一个新属性,它会立即被拾取:

SQL>  insert into properties values (4, 'StarSign')
   2  /

1 row created.

SQL>  insert into propertyvalues values (4, 2, 'Aries')
  2  /

1 row created.

SQL> exec :rc := get_eav_view

PL/SQL procedure successfully completed.

SQL> print rc

CUSTOMERID
----------
CUSTOMERNAME
--------------------------------------------------------------------------------
AGE
--------------------------------------------------------------------------------
WEIGHT
--------------------------------------------------------------------------------
FAVOURITEICECREAM
--------------------------------------------------------------------------------
STARSIGN
--------------------------------------------------------------------------------
         1
Bob
34
80KG
Cherry Garcia


         2
Tom
24
53KG

Aries


SQL>

【讨论】:

太棒了!和一个很好的例子。嗯。樱桃加西亚。

以上是关于从 Oracle/Mysql 中的通用数据创建 [物化] 视图的主要内容,如果未能解决你的问题,请参考以下文章

如何从数据库(oracle,mysql)中取出根据ID分组后,时间最大的数据

如何使用接口从C ++中的模板强制通用数据类型?

sqoop Mysql 导入到hdfshive

jdbc -- 001 -- 一般方式创建数据库连接(oracle/mysql)

访问从 Reactjs 中的状态创建的数组的数据时出现问题

如何从 rexx 创建***通用 racf 配置文件