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

Posted

技术标签:

【中文标题】在 oracle apex 中将 sql 查询重写为 pl/sql【英文标题】:rewriting sql query to pl/sql in oracle apex 【发布时间】:2021-04-29 16:44:40 【问题描述】:

我在 oracle apex 中有一个应用程序,其中有一个名为 search_result 的部分,它返回此 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;

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

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

【问题讨论】:

【参考方案1】:

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

BEGIN
  return 'SELECT * FROM MOVIES';
END;

使用您在 cmets 中提供的选择,您需要使用两个单引号来表示您返回的字符串中的一个引号。

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;

【讨论】:

我试过这样做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; 但它会抛出此错误 ORA-06550:第 7 行,第 4 列:PLS-00103:在预期以下之一时遇到符号“HTTPS”:* & = - + ; > at in is mod 余数 not rem )> or != or ~= >= and or like like2 like4 likec between ||多集成员子多集** 您选择的语法不正确。您需要在查询中的字符串周围使用'' 而不是'。查看更新的答案。【参考方案2】:

您的代码大部分是正确的。但是,您已将其编写为匿名块,遗憾的是无法返回结果。您需要转换为返回 reference cursor 的函数或带有引用游标的 out 参数的过程。

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;

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

处理:

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;    

函数被编译并存储在数据库中(存储过程)。 ref-cursor 是查询的结果集 - 正如您的 Apex 部分不通过查询的结果集返回查询一样。


如何充分使用参考光标。 (主要是)。响应错误类型异常。 此错误是由于您的查询返回的列与表中定义的列不同,但随后尝试获取定义为 movies%rowtype 的变量;现在该定义创建了一个与表列定义完全匹配的结构。但是,您的查询至少有 4 个不属于表定义的列,可能还有 3 个其他列。 Title、Production_Company 和 Poster_Path 列在查询中分别使用了两次。即使有别名,它们仍然代表结果集中的一个附加列。有函数调用和空选择。此外,表中似乎还有其他列不在查询中。这不会使查询出错,只是它无法匹配movies%rowtype 声明。 想到了两个解决方案。只需“从电影中选择 *”并获取 movies%rowtype 声明并在检索表数据后派生其他列。另一种是在包规范中设置适当的游标定义。它可以在包的外部引用。问题是当您实际打开参考游标时,您基本上需要在正文中重复该查询。 假设您确实需要这些列,并且您有不想选择的表列,因为您不需要它们(我喜欢那部分),我整理了一个full demo。因为我没有你的表定义,而且我完全不知道函数 apex_string.get_initials 是什么,所以我只是为他们做了一些事情。但它们似乎是合理的,你应该用实际替换。

【讨论】:

所以我需要创建单独的函数,它将在我的数据库中返回这个查询,然后在这个 pl/sql 函数体中返回它,对吧? 不完全,我已经更新了答案以显示它是如何使用的,但是它涉及一个单独的功能? 基本上,我应该使用我在 sql 查询中使用的自己的查询在我的数据库中创建这个函数,然后在pl/sql function body returning SQL query 中编写这个 processing 代码? 据我所知,我应该返回而不是仅仅打印这个光标以便与 html 元素交互 是的。印刷只是为了演示目的。在循环中,您可以使用任何需要的代码操作。

以上是关于在 oracle apex 中将 sql 查询重写为 pl/sql的主要内容,如果未能解决你的问题,请参考以下文章

不能在 sql 查询 APEX ORACLE 中使用绑定变量作为表名

如何在 oracle apex 18 中编辑交互式网格(带有复杂的 sql 查询)?

Oracle APEX - 将隐藏的 SQL 查询下载到 CSV

Apex Oracle 中的 SQL 多对多查询

Oracle APEX 文本页面项作为 SQL 查询中的不可编辑超链接字段

运行时解析 PL/SQL 的 Oracle Apex Cards 视图