【问题标题】:Creating a [materialised]view from generic data in Oracle/Mysql从 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

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

【问题讨论】:

    标签: sql mysql oracle view pivot


    【解决方案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>
    

    【讨论】:

    • 太棒了!和一个很好的例子。嗯。樱桃加西亚。
    猜你喜欢
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多