在 oracle apex 中将 sql 查询重写为 pl/sql

rewriting sql query to pl/sql in oracle apex

我在 oracle apex 中有一个应用程序,有一个名为 search_result 的部分,它 return 是这个 sql 查询

select
  "TITLE" CARD_TITLE,
  "POSTER_PATH" CARD_TEXT,
  "PRODUCTION_COMPANY" CARD_SUBTEXT,
  apex_string.get_initials("TITLE") CARD_INITIALS,
  'https://www.imdb.com/title/'||IMDB_ID CARD_LINK,
  null CARD_MODIFIERS,
  null CARD_COLOR,
  null CARD_ICON,
  "GENRE",
  "COUNTRY",
  "PRODUCTION_COMPANY",
  "RUNTIME",
  "BUDGET",
  "VOTE_AVERAGE",
  "TITLE",
  "POSTER_PATH"
from  "MOVIES"
order by vote_average desc

但我需要用 pl/sql 函数体和 我创建了功能包

    CREATE OR REPLACE PACKAGE PRINTS AS
FUNCTION MOVIES_LIST RETURN SYS_REFCURSOR;
FUNCTION ORDER_VOTE RETURN SYS_REFCURSOR;
END PRINTS;


CREATE OR REPLACE PACKAGE BODY PRINTS AS
FUNCTION ORDER_VOTE
RETURN SYS_REFCURSOR
is 
    r_movie sys_refcursor;
BEGIN
open r_movie for select
  "TITLE" CARD_TITLE,
  "POSTER_PATH" CARD_TEXT,
  "PRODUCTION_COMPANY" CARD_SUBTEXT,
  apex_string.get_initials("TITLE") CARD_INITIALS,
  null CARD_MODIFIERS,
  null CARD_COLOR,
  null CARD_ICON,
  "GENRE",
  "COUNTRY",
  "PRODUCTION_COMPANY",
  "RUNTIME",
  "BUDGET",
  "VOTE_AVERAGE",
  "TITLE",
  "POSTER_PATH"
from  "MOVIES"
order by vote_average desc;
return r_movie;
END ORDER_VOTE;
END PRINTS;

然后我尝试 return 在 pl/sql returning sql 查询块中 return 这个游标 :

declare 
   movie_cur sys_refcursor;
   a_movie   movies%rowtype; 
begin

   movie_cur := PRINTS.ORDER_VOTE;            -- call the movie function

   loop
      fetch movie_cur into a_movie;
      exit when movie_cur%notfound; 
   end loop; 
   return a_movie;
end;

但是它抛出这个错误: ORA-06550:第 12 行,第 11 列:PLS-00382:表达式类型错误

我做错了什么,我该如何解决。

我的数据库和一些截图:

Column Name Data Type   Nullable    Default Primary Key
ID  NUMBER  No  "WKSP_DBMSPROJECT1"."ISEQ$$_111377832".nextval  1
TITLE   VARCHAR2(255)   Yes -   -
GENRE   VARCHAR2(50)    Yes -   -
COUNTRY VARCHAR2(50)    Yes -   -
PRODUCTION_COMPANY  VARCHAR2(255)   Yes -   -
RUNTIME NUMBER  Yes -   -
RELEASE_DATE    DATE    Yes -   -
OVERVIEW    VARCHAR2(4000)  Yes -   -
TAGLINE VARCHAR2(255)   Yes -   -
BUDGET  NUMBER  Yes -   -
REVENUE NUMBER  Yes -   -
POPULARITY  NUMBER  Yes -   -
VOTE_AVERAGE    NUMBER  Yes -   -
VOTE_COUNT  NUMBER  Yes -   -
POSTER_PATH VARCHAR2(255)   Yes -   -
TMDB_ID NUMBER  Yes -   -
IMDB_ID VARCHAR2(50)    Yes -   -

IMDB DB

page design

page itself

当使用 PL/SQL Function Body returning SQL Query 类型时,您需要 return 您的 SQL 语句作为字符串。所以你所在地区的来源应该是这样的:

BEGIN
  return 'SELECT * FROM MOVIES';
END;

使用您在评论中提供的 select,您需要使用两个单引号来表示您正在 returning 的字符串中的引号。

BEGIN
    RETURN 'SELECT "TITLE"                            CARD_TITLE,
         "POSTER_PATH"                                CARD_TEXT,
         "PRODUCTION_COMPANY"                         CARD_SUBTEXT,
         apex_string.get_initials ("TITLE")           CARD_INITIALS,
         ''https://www.imdb.com/title/'' || IMDB_ID   CARD_LINK,
         NULL                                         CARD_MODIFIERS,
         NULL                                         CARD_COLOR,
         NULL                                         CARD_ICON,
         "GENRE",
         "COUNTRY",
         "PRODUCTION_COMPANY",
         "RUNTIME",
         "BUDGET",
         "VOTE_AVERAGE",
         "TITLE",
         "POSTER_PATH"
    FROM "MOVIES"
ORDER BY vote_average DESC';
END;

您的代码大部分是正确的。但是你已经将它写成一个匿名块,不幸的是不能 return 结果。您需要转换为 return 为 reference cursor 的函数或带有参考游标输出参数的过程。

create or replace 
function movies_list
  return sys_refcursor 
is
    r_movies sys_refcursor;
begin
   open r_movies for 
        select * from movies;
    return r_movies;
end movies_list;

因为您当前的代码似乎处理的是列列表而不是 select *。在这种情况下,您可以 select 使用您的确切查询。

处理中:

declare 
   movie_cur sys_refcursor;
   a_movie   movies%rowtype; 
begin
   dbms_output.enable; 
   movie_cur := movies_list;            -- call the movie function
   dbms_output.put_line("Movie List');      
   loop
      fetch movie_cur into a_movie;       
      exit when movie_cur%not_found; 
      dbms_output.put_line(a_movie.title); 
   end loop; 
end;    

该函数被编译并存储在数据库中(一个存储过程)。 THE ref-cursor 是查询的结果集——就像你的 Apex 部分没有 return 查询一样,通过查询的结果集。


如何完整使用引用游标。 (主要是)。响应错误类型异常。

此错误是由于您的查询 return 与 table 中定义的列不同,但随后试图提取到定义为 movies%rowtype 的变量;现在该定义创建了一个与 tables 列定义完全匹配的结构。但是,您的查询至少有 4 列不属于 table 定义的一部分,可能还有 3 列。 Title、Production_Company 和 Poster_Path 列在查询中各使用了两次。即使使用了别名,它们仍然代表结果集中的一个附加列。有函数调用和空 select 离子。此外,table 中似乎还有其他列不在查询中。这不会使查询变坏,只是它无法匹配 movies%rowtype 声明。

我想到了两种解决方案。只需“select * from movies”并获取到 movies%rowtype 声明并在检索 table 数据后派生附加列。另一种是在包规范中设置适当的游标定义。它可以在包的外部引用。问题是当您实际打开引用游标时,您基本上需要在正文中重复该查询。

假设您确实需要这些列,并且您有 table 列,您希望避免 selecting 因为您不需要它们(我喜欢那部分),我将 full demo 放在一起。由于我没有您的 table 定义,而且我完全不知道 apex_string.get_initials 函数是什么,所以我只是为它们做了一些补充。不过貌似挺有道理的,换成实际应该会出问题。