【问题标题】:Can views be created in PL/SQL Functions?可以在 PL/SQL 函数中创建视图吗?
【发布时间】:2021-08-21 12:58:56
【问题描述】:

我刚开始学习 PL/SQL。我的问题是可以在函数中创建视图吗?

CREATE OR REPLACE FUNCTION most_sold_item(in_year INT)
RETURN INT
IS

most_shipped_item INT := 0;

BEGIN
    CREATE OR REPLACE VIEW Shipped_Items AS
    SELECT ITEM_ID,SUM(QUANTITY) AS Total_Quantity 
    FROM ORDERS, ORDER_ITEMS
    WHERE Orders.Order_ID =Order_Items.Order_ID
    AND Status=1
    AND Order_Year=in_year
    GROUP BY Item_ID;

    SELECT Item_ID
    INTO most_shipped_item
    FROM Shipped_Items
    WHERE Total_quantity=(
    SELECT MAX(Total_Quantity)
    FROM Shipped_Items);
    

    return  most_shipped_item;
 
END;
/

这是我的代码。似乎有某种我找不到的错误。谁能帮我解决这个问题? 谢谢。

Here's the snippet of the datatbase that I'm working on

【问题讨论】:

  • 否;使用CTE
  • 另外,你有一个逻辑问题,即使可以做到。如果MAX 匹配多个Item_IDs,您将产生多个结果并产生错误。你也不需要VIEW。这可以在没有VIEW 的语句中完成,只要您包含打破任何联系的逻辑即可。

标签: sql plsql


【解决方案1】:

如果您希望为此使用函数(添加了打破关系的逻辑),以下是您可能会做什么的粗略想法:

-- Estimated structure based on posted image:

CREATE TABLE orders (
   order_id     int primary key
 , client_id    int
 , order_year   int
 , status       int
);

CREATE TABLE order_items (
   order_id     int
 , item_id      int
 , quantity     int
 , ppu          int
 , primary key (order_id, item_id)
);

-- The adjusted function:

CREATE OR REPLACE FUNCTION most_sold_item(in_year INT)
RETURN INT
IS

most_shipped_item INT := 0;

BEGIN

   WITH shipped_items AS (
             SELECT ITEM_ID, SUM(QUANTITY) AS Total_Quantity 
               FROM ORDERS, ORDER_ITEMS
              WHERE Orders.Order_ID =Order_Items.Order_ID
                AND Status=1
                AND Order_Year=in_year
              GROUP BY Item_ID
        )
    SELECT Item_ID
      INTO most_shipped_item
      FROM Shipped_Items
     WHERE Total_quantity=(
         SELECT MAX(Total_Quantity)
           FROM Shipped_Items
        )
     ORDER BY item_id
     FETCH FIRST 1 ROW ONLY
    ;

    return  most_shipped_item;
 
END;
/

不要忘记保护多个item_id 匹配MAX 的情况。这很容易做到,但我不知道你希望如何处理这种情况。我已调整上述解决方案以防止出现此问题。

问题编辑队列已满。这是一个可以添加到问题中的可执行测试用例(没有数据):

Executable test case, derived from the posted image (without data)

【讨论】:

  • 非常感谢您与我们联系。你能告诉我如何在不使用视图的情况下完成吗?
  • @lto 上述解决方案不使用VIEW。正如@Stu 评论的那样,这使用了WITH clause,称为Common Table Expression (CTE)。它是标准 SQL 的一部分。它类似于VIEW,但实际上更强大,并且不需要在数据库中创建具体对象。
  • 哦,好吧。你提到这可以用一个语句来完成,你能说一下它是如何完成的吗?这对我有很大的帮助。
  • @lto 这基本上是一种说法。您可以在函数外部执行此操作,只需参数化 in_year 详细信息,例如,使用准备好的语句。如果使用得当,一个功能是可以的。如果不了解更多有关您如何使用该功能的信息,很难提供太多详细信息。随意就您对函数的使用提出不同的问题。
【解决方案2】:

回答您的“原始”问题:

可以在 PL/SQL 函数中创建视图吗?

是的,他们可以。你应该这样做吗?绝对不是,这不是 Oracle 的工作方式(在大多数情况下)。在 Oracle 中,我们在 SQL 级别创建对象并在 SQL 或 PL/SQL 中使用它们,但我们不会从 PL/SQL 创建它们。

不管怎样,你来了;在代码中读取 cmets。我使用了 Scott 的示例模式,因为我没有您的表,但原理保持不变。

功能:

SQL> create or replace function f_test(par_deptno in number)
  2    return number
  3  is
  4    -- you can't perform DDL in PL/SQL procedures unless they are
  5    -- autonomous transactions
  6    pragma autonomous_transaction;
  7    retval number;
  8  begin
  9    -- you can't perform DML in a function unless you use dynamic SQL
 10    execute immediate
 11      'create or replace view v_emp as ' ||
 12      '  select ename, sal ' ||
 13      '  from emp ' ||
 14      '  where deptno = ' || dbms_assert.enquote_literal(par_deptno);
 15
 16    -- you can't use an ordinary SELECT statement because at time of
 17    -- procedure compilation view V_EMP doesn't exist yet, so compile
 18    -- would fail
 19    execute immediate
 20      'select sum(sal) from v_emp ' into retval;
 21
 22    return retval;
 23  end;
 24  /

Function created.

测试:

SQL> select f_test (20) from dual;

F_TEST(20)
----------
     10875

视图包含什么?

SQL> select * from v_emp;

ENAME             SAL
---------- ----------
SMITH             800
JONES            2975
SCOTT            3000
ADAMS            1100
FORD             3000

SQL>

【讨论】:

    猜你喜欢
    • 2019-08-05
    • 2017-08-16
    • 2010-11-07
    • 2019-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    相关资源
    最近更新 更多