从 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分组后,时间最大的数据