我有一个包含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');
我想要做的是创建一个视图,其中包含属性中所有ROWS的列,并在Customers中包含条目。列值从PropertyValues填充。
例如
customerId Age Weight
1 34 80KG
2 24 53KG
我认为我需要一个存储过程来执行此操作,也许需要一个物化视图(表“属性”中的条目很少更改)。 有什么提示吗?
答案 0 :(得分:2)
使用动态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)。我不确定为什么会这样,但是当我改用旧的连接技术时,问题就消失了,这很烦人,因为外部连接语法很笨拙。
无需重新创建数据库对象的解决方案是在函数中使用动态SQL,该函数返回Ref Cursor,映射到JDBC ResultSet:
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>