是否可以在PL SQL过程中创建本地视图?

时间:2015-03-10 18:09:55

标签: oracle plsql

我正在寻找一种解决方案,告诉Oracle" 此查询意味着像视图一样重复使用" (如果我问的话,如果可能的话,我不想/不能创建完整的全局视图。)

使用以下最小模型(我遗漏了其他列):

  • 所有者拥有图书
  • 图书包含作者章节
  • 章节书籍(例如:本书其他格式中包含的章节)和作者
  • authors 至少有一个_authors_related_data1_和几个_authors_related_data2_。使用_authors_related_data3_,...,__uthors_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能够优化此类用例。
  • 出于各种(和合法的)原因,我不能。

2 个答案:

答案 0 :(得分:1)

您可以使用表函数或流水线函数

以下是表函数的示例: 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;

答案 1 :(得分:0)

这样的程序会满足您的需求吗?

  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选为double,而你可以用你的复杂查询替换它并定义变量来相应地获取)

实际的通话可能是这样的:

   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;