是否可以在 PL SQL 程序中创建本地视图?
Is it possible to create a local view in PL SQL procedure?
我正在寻找一个解决方案,告诉 Oracle“这个查询应该像视图一样被重用”(如果我问,那是我不想要的to/can如果可能,不要创建完整的全局视图。
使用以下最小模型(我省略了其他列):
- 有所有者拥有本书。
- 本书有作者和章节。
- 一个章节有本书(例如:本书的另一种格式中包含的章节)和作者.
- 一个作者至少有一个_authors_related_data1_和几个_authors_related_data2_。 _authors_related_data3_, ..., _authors_related_dataN_.
也是如此
因此下面的创建语句(我没有针对Oracle验证它们,更多的是为了理解问题
比测试)。
create table owners( owner_id number not null, constraint pk_owners primary key (owner_id));
create table books( book_id number not null, constraint pk_books primary key (book_id));
create table authors( author_id number not null, constraint pk_authors primary key (author_id));
create table chapters( chapter_id number not null, constraint pk_chapters primary key (chapter_id));
create table owned_books(
owner_id number not null,
book_id number not null,
constraint pk_owned_books primary key (owner_id, book_id),
constraint fk_owned_books_1 foreign key (owner_id) references owners (owner_id),
constraint fk_owned_books_2 foreign key (book_id) references books (book_id)
);
create table book_authors(
book_id number not null,
author_id number not null,
constraint pk_book_authors primary key (book_id, author_id),
constraint fk_book_authors_1 foreign key (author_id) references authors (author_id),
constraint fk_book_authors_2 foreign key (book_id) references books (book_id)
);
create table chapter_authors(
chapter_id number not null,
author_id number not null,
constraint pk_chapter_authors primary key (chapter_id, author_id),
constraint fk_chapter_authors_1 foreign key (author_id) references authors (author_id),
constraint fk_chapter_authors_2 foreign key (chapter_id) references chapters (chapter_id)
);
create table book_chapters(
chapter_id number not null,
book_id number not null,
constraint pk_book_chapters primary key (chapter_id, book_id),
constraint fk_book_chapters_1 foreign key (chapter_id) references chapters (chapter_id)
constraint fk_book_chapters_2 foreign key (book_id) references books (book_id)
);
create table authors_related_data1(
author_id number not null,
constraint pk_authors_related_data1 primary key (author_id),
constraint fk_authors_related_data1_1 foreign key (author_id) references authors (author_id)
);
create table authors_related_data2(
data_id number not null,
author_id number not null,
constraint pk_authors_related_data2 primary key (data_id),
constraint authors_related_data2 foreign key (author_id) references authors (author_id)
);
我想做的查询(和重复的部分):
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
where owned_books.owner_id = P_OWNER_ID
), v_authors as (
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
select authors_related_data1.*
from v_authors
inner join authors_related_data1 on authors_related_data1.author_id = v_authors.author_id
;
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
where owned_books.owner_id = P_OWNER_ID
), v_authors as (
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
select authors_related_data2.*
from v_authors
inner join authors_related_data2 on authors_related_data2.author_id = v_authors.author_id
;
两个查询的第一部分(带有...)相同。
这样的景色会很棒:
create view v_owned_authors as (
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
)
(
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
;
之前的查询会很简单:
select authors_related_data2.*
from v_owned_authors
inner join authors_related_data2 on authors_related_data2.author_id = v_authors.author_id
where v_owned_authors.owner_id = P_OWNER_ID
但是:
- 拥有的书籍集可能太大,视图不会有 P_OWNER_ID 参数和减少拥有的书籍子句。因此,出于性能原因,我想避免使用该视图,因为我认为 Oracle 无法优化此类用例。
- 出于各种(合法的)原因,我不能。
这样的流程能满足您的需求吗?
create or replace procedure p_statement (cur in out sys_refcursor)
is
begin
open cur for
select 1 num from dual union select 2 num from dual;
end;
(我把 select 从 dual 放在那里,相反你可以用你的复杂查询替换它并相应地定义要提取的变量)
实际调用可能是这样的:
declare
mycur sys_refcursor;
num number;
begin
p_statement(mycur);
LOOP
FETCH mycur INTO num;
EXIT WHEN mycur%NOTFOUND;
DBMS_OUTPUT.put_line(num);
END LOOP;
end;
您可以使用 table 函数或流水线函数
这是一个 table 函数的示例,来自:
http://oracle-base.com/articles/misc/pipelined-table-functions.php
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER,
description VARCHAR2(50)
);
/
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf (p_rows IN NUMBER) RETURN t_tf_tab AS
l_tab t_tf_tab := t_tf_tab();
BEGIN
FOR i IN 1 .. p_rows LOOP
l_tab.extend;
l_tab(l_tab.last) := t_tf_row(i, 'Description for ' || i);
END LOOP;
RETURN l_tab;
END;
/
-- Test it.
SELECT *
FROM TABLE(get_tab_tf(10))
ORDER BY id DESC;
这是流水线函数的示例:
CREATE OR REPLACE FUNCTION get_tab_ptf (p_rows IN NUMBER) RETURN t_tf_tab PIPELINED AS
r t_tf_row%rowtype;
BEGIN
for z in (select id, desc from sometalbe) loop
r.id := z.id;
r.description := z.desc;
PIPE ROW(r);
END LOOP;
RETURN;
END;
我正在寻找一个解决方案,告诉 Oracle“这个查询应该像视图一样被重用”(如果我问,那是我不想要的to/can如果可能,不要创建完整的全局视图。
使用以下最小模型(我省略了其他列):
- 有所有者拥有本书。
- 本书有作者和章节。
- 一个章节有本书(例如:本书的另一种格式中包含的章节)和作者.
- 一个作者至少有一个_authors_related_data1_和几个_authors_related_data2_。 _authors_related_data3_, ..., _authors_related_dataN_. 也是如此
因此下面的创建语句(我没有针对Oracle验证它们,更多的是为了理解问题 比测试)。
create table owners( owner_id number not null, constraint pk_owners primary key (owner_id));
create table books( book_id number not null, constraint pk_books primary key (book_id));
create table authors( author_id number not null, constraint pk_authors primary key (author_id));
create table chapters( chapter_id number not null, constraint pk_chapters primary key (chapter_id));
create table owned_books(
owner_id number not null,
book_id number not null,
constraint pk_owned_books primary key (owner_id, book_id),
constraint fk_owned_books_1 foreign key (owner_id) references owners (owner_id),
constraint fk_owned_books_2 foreign key (book_id) references books (book_id)
);
create table book_authors(
book_id number not null,
author_id number not null,
constraint pk_book_authors primary key (book_id, author_id),
constraint fk_book_authors_1 foreign key (author_id) references authors (author_id),
constraint fk_book_authors_2 foreign key (book_id) references books (book_id)
);
create table chapter_authors(
chapter_id number not null,
author_id number not null,
constraint pk_chapter_authors primary key (chapter_id, author_id),
constraint fk_chapter_authors_1 foreign key (author_id) references authors (author_id),
constraint fk_chapter_authors_2 foreign key (chapter_id) references chapters (chapter_id)
);
create table book_chapters(
chapter_id number not null,
book_id number not null,
constraint pk_book_chapters primary key (chapter_id, book_id),
constraint fk_book_chapters_1 foreign key (chapter_id) references chapters (chapter_id)
constraint fk_book_chapters_2 foreign key (book_id) references books (book_id)
);
create table authors_related_data1(
author_id number not null,
constraint pk_authors_related_data1 primary key (author_id),
constraint fk_authors_related_data1_1 foreign key (author_id) references authors (author_id)
);
create table authors_related_data2(
data_id number not null,
author_id number not null,
constraint pk_authors_related_data2 primary key (data_id),
constraint authors_related_data2 foreign key (author_id) references authors (author_id)
);
我想做的查询(和重复的部分):
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
where owned_books.owner_id = P_OWNER_ID
), v_authors as (
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
select authors_related_data1.*
from v_authors
inner join authors_related_data1 on authors_related_data1.author_id = v_authors.author_id
;
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
where owned_books.owner_id = P_OWNER_ID
), v_authors as (
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
select authors_related_data2.*
from v_authors
inner join authors_related_data2 on authors_related_data2.author_id = v_authors.author_id
;
两个查询的第一部分(带有...)相同。
这样的景色会很棒:
create view v_owned_authors as (
with v_books as (
select books.book_id
from owned_books
inner join books on books.book_id = owned_books.book_id
)
(
select authors.author_id
from v_books
inner join book_authors on book_authors.book_id = v_books.book_id
inner join authors on authors.author_id = book_authors.author_id
union
select authors.author_id
from v_books
inner join book_chapters on book_chapters.book_id = v_books.book_id
inner join chapter_authors on chapter_authors.chapter_id = book_chapters.chapter_id
inner join authors on authors.author_id = book_chapters.author_id
)
;
之前的查询会很简单:
select authors_related_data2.*
from v_owned_authors
inner join authors_related_data2 on authors_related_data2.author_id = v_authors.author_id
where v_owned_authors.owner_id = P_OWNER_ID
但是:
- 拥有的书籍集可能太大,视图不会有 P_OWNER_ID 参数和减少拥有的书籍子句。因此,出于性能原因,我想避免使用该视图,因为我认为 Oracle 无法优化此类用例。
- 出于各种(合法的)原因,我不能。
这样的流程能满足您的需求吗?
create or replace procedure p_statement (cur in out sys_refcursor)
is
begin
open cur for
select 1 num from dual union select 2 num from dual;
end;
(我把 select 从 dual 放在那里,相反你可以用你的复杂查询替换它并相应地定义要提取的变量)
实际调用可能是这样的:
declare
mycur sys_refcursor;
num number;
begin
p_statement(mycur);
LOOP
FETCH mycur INTO num;
EXIT WHEN mycur%NOTFOUND;
DBMS_OUTPUT.put_line(num);
END LOOP;
end;
您可以使用 table 函数或流水线函数
这是一个 table 函数的示例,来自: http://oracle-base.com/articles/misc/pipelined-table-functions.php
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER,
description VARCHAR2(50)
);
/
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf (p_rows IN NUMBER) RETURN t_tf_tab AS
l_tab t_tf_tab := t_tf_tab();
BEGIN
FOR i IN 1 .. p_rows LOOP
l_tab.extend;
l_tab(l_tab.last) := t_tf_row(i, 'Description for ' || i);
END LOOP;
RETURN l_tab;
END;
/
-- Test it.
SELECT *
FROM TABLE(get_tab_tf(10))
ORDER BY id DESC;
这是流水线函数的示例:
CREATE OR REPLACE FUNCTION get_tab_ptf (p_rows IN NUMBER) RETURN t_tf_tab PIPELINED AS
r t_tf_row%rowtype;
BEGIN
for z in (select id, desc from sometalbe) loop
r.id := z.id;
r.description := z.desc;
PIPE ROW(r);
END LOOP;
RETURN;
END;