下面的代码有什么问题?它告诉我不能在表上创建触发器,但我正在视图上创建(Orders_MV)

发布于 2024-10-20 09:32:00 字数 800 浏览 2 评论 0原文

可能的重复:
为什么此触发器失败?它说标识符无效。

CREATE MATERIALIZED VIEW ORDERS_MV

BUILD IMMEDIATE

REFRESH COMPLETE ON DEMAND AS

SELECT * FROM ORDERS;

CREATE OR REPLACE TRIGGER update_ship_receive

INSTEAD OF INSERT ON ORDERS_MV

FOR EACH ROW

BEGIN

  UPDATE ORDERS SET EXPECTED_SHIP_DATE = ORDER_DATE+5;

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+1 
WHERE SHIPPING_METHOD = '1 DAY';

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+2
 WHERE SHIPPING_METHOD = '2 DAY';

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+5 
WHERE SHIPPING_METHOD = 'GROUND';

END;
/

Possible Duplicate:
Why does this trigger fail? It says invalid identifier.

CREATE MATERIALIZED VIEW ORDERS_MV

BUILD IMMEDIATE

REFRESH COMPLETE ON DEMAND AS

SELECT * FROM ORDERS;

CREATE OR REPLACE TRIGGER update_ship_receive

INSTEAD OF INSERT ON ORDERS_MV

FOR EACH ROW

BEGIN

  UPDATE ORDERS SET EXPECTED_SHIP_DATE = ORDER_DATE+5;

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+1 
WHERE SHIPPING_METHOD = '1 DAY';

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+2
 WHERE SHIPPING_METHOD = '2 DAY';

  UPDATE ORDERS SET EXPECTED_RECEIVE_DATE = SHIP_DATE+5 
WHERE SHIPPING_METHOD = 'GROUND';

END;
/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柠檬 2024-10-27 09:32:00

这是行不通的,因为物化视图不是视图,而是一种特殊类型的表:它有数据,我们可以用它强制约束等等。

因此,在解决这个问题后,让我们看看您的底层流程逻辑,这很令人困惑。您有一个基于表的物化视图。现在您想要构建一个触发器,每当将行插入到物化视图中时,该触发器都会更新基表。

  1. 您希望物化视图包含更改的数据吗?

  2. 由于您指定 SQL 的方式,触发器(如果它可以工作)将更新 ORDERS 表中的每一行。

  3. 因为触发器是 FOR EACH ROW,刷新物化视图会多次更新整个 ORDERS 表,每次更新 ORDERS 表中的每一行。

  4. INSTEAD OF 触发器执行触发器主体中的代码,而不是(而不是)触发器标头中指定的操作。因此(如果它可以工作)触发器将更新 ORDERS 表并且不向物化视图中插入任何行。

所以我希望您能够看到这个错误正在阻止您犯下更严重的架构错误。您需要做的是阐明您的业务流程,然后尝试用 SQL 来表达它。在我看来,最合适的解决方案是 ORDERS 表上的 BEFORE UPDATE 触发器。像这样的事情:

CREATE OR REPLACE TRIGGER update_ship_receive
    BEFORE INSERT or UPDATE ON ORDERS
    FOR EACH ROW
BEGIN

    if :new.EXPECTED_SHIP_DATE is null
    then
        :new.EXPECTED_SHIP_DATE = :new.ORDER_DATE+5;
    end if;

    if :new.EXPECTED_RECEIVE_DATE is null
    then 
        case :new.SHIPPING_METHOD
            when '1 DAY' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+1; 
            when '2 DAY' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+2;
            when 'GROUND' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+5; 
            else
               null;
         end case;
    end if;
END;
/

然后,您只有一个简单的物化视图,刷新它时不需要进行任何关联的处理。显然,您的实际业务逻辑可能决定不同的解决方案。

This doesn't work because a materialized view is not a view it is a special kind of table: it has data, we can enforce constraints with it, etc.

So having got that out of the way let's look at your underlying process logic, which is confusing. You have a materialized view based on a table. Now you want to build a trigger which updates the base table whenever a row is inserted into the materialized view.

  1. Do you expect the materialized view to contain the changed data?

  2. Because of the way you have specified the SQL the trigger (if it could work) would update every row in the ORDERS table.

  3. Because the trigger is FOR EACH ROW refreshing the materialized view would update the entire ORDERS table multiple times, once for each row in the ORDERS table.

  4. INSTEAD OF triggers execute the code in the trigger body rather than (instead of) the action specified in the trigger header. So (if it could work) the trigger would update the ORDERS table and insert no rows into the materialized view.

So I hope you can see that this error is preventing you from making a more serious architectural error. What you need to do is clarify your business process and then seek to express that in SQL. To my mind, the most appropriate solution would be a BEFORE UPDATE trigger on the ORDERS table. Something like this:

CREATE OR REPLACE TRIGGER update_ship_receive
    BEFORE INSERT or UPDATE ON ORDERS
    FOR EACH ROW
BEGIN

    if :new.EXPECTED_SHIP_DATE is null
    then
        :new.EXPECTED_SHIP_DATE = :new.ORDER_DATE+5;
    end if;

    if :new.EXPECTED_RECEIVE_DATE is null
    then 
        case :new.SHIPPING_METHOD
            when '1 DAY' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+1; 
            when '2 DAY' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+2;
            when 'GROUND' then        
               :new.EXPECTED_RECEIVE_DATE = :new.SHIP_DATE+5; 
            else
               null;
         end case;
    end if;
END;
/

You then just have a simple materialized view with no associated processing to undertake when you refresh it. Obviously your actual business logic may dictate a different solution.

苦妄 2024-10-27 09:32:00

物化视图不是常规视图。它有一个与之相关的数据段。

A materialized view isn't a regular view. It has a data segment related to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文