【问题标题】:SQL Server to Oracle Language TranslatorSQL Server 到 Oracle 语言翻译器
【发布时间】:2019-02-23 12:44:44
【问题描述】:

我在 Microsoft SQL Server 中创建了一个触发器,我正试图将其引入 Oracle SQL Developer。我意识到语法和语言有点不同。我正在缓慢但肯定地尝试通过每一行,但非常感谢任何帮助或指导。

我尝试将 Microsoft SQL Server 中的触发器转移到 Oracle:

CREATE TRIGGER Production.Product_Price_Check
ON AdventureWorks.Production.Product FOR UPDATE
AS 
    DECLARE @min_price money; --to keep minimum price
    DECLARE @new_price money; --to keep new price from update query

    SELECT @min_price = (SELECT StandardCost*1.2 FROM INSERTED);
    SELECT @new_price = (SELECT ListPrice FROM INSERTED)
    IF @new_price < @min_price
       BEGIN
            ROLLBACK TRANSACTION
            -- Rolls back an explicit or implicit transaction to the beginning of the transaction
            PRINT('the price can’t be below ' + cast(@min_price as varchar(20)));
            -- cast is used to convert one data type to another one 
            RAISERROR ('statement was aborted', 6, 1) ;
            return; 
    ELSE PRINT ('Price was successfully changed');     
    END   

GO

我将在我正在研究的过程中使用新触发器发布我所在位置的更新:

UPDATE Product set ListPrice=42.00 WHERE ProductID=514;

更新代码:

CREATE OR REPLACE
TRIGGER Product_Price_Check
   BEFORE UPDATE ON Product
   FOR EACH ROW
       BEGIN
         IF :new.listprice < :new.standardcost * 1.2 then
         raise_application_error(-20999, 'The price can not be below' || to_char(:new.standardcost * 1.2));
         RETURN;
         ELSE
           dbms_output.put_line('Price was sucessfully changed');
         END IF;
END;

快速创建我正在使用的表的示例代码:

CREATE TABLE Product(
    productID int Primary Key,
    name VARCHAR(250),
    ListPrice int Primary Key,
    StandardCost NUMBER(10,4),
);

INSERT INTO Product VALUES(514, 'NLL Mountain Seat Assembly', 133.3400, 98.7700);

【问题讨论】:

  • 我们无法为您编写代码,如果您展示您的尝试以及您面临的具体错误,您将获得一些帮助
  • 你不能在触发器中rollback
  • 为什么要复制损坏的触发器? inserted 可以包含 0、1 或 多个 行。此触发器使用该表中的两个单独的SELECTs 设置变量,这将采用一行的值并忽略其余的值(不保证它们甚至来自同一行)。起点不好。
  • 另外,看起来这应该只是一个CHECK 约束。
  • 我是这个超级新手

标签: oracle plsql database-trigger


【解决方案1】:

在 Oracle 或 SQL Server 中,触发器似乎是不必要的,您应该改写:

ALTER TABLE Production.Product ADD CONSTRAINT CK_Product_Prices
CHECK (ListPrice >=StandardCost * 1.2);

这完全避免了编写任何过程逻辑,而是使用声明性规则。这些通常是首选,因为有时优化器可以利用它们来消除查询中不可能产生任何结果的部分。

【讨论】:

    【解决方案2】:

    Oracle 和 SQL Server 中的触发器之间最根本的区别是,Oracle 默认使用 行级 触发器 - 这是 SQL Server 不提供的。据我所知,您要做的就是检查更新行的新值是否符合某些规则。

    CREATE or replace TRIGGER Product_Price_Check_trg
      BEFORE UPDATE ON Product 
      FOR EACH ROW -- this makes it a row level trigger
    AS 
    begin
      if :new.listprice < :new.standardcost * 1.2 then 
        raise_application_error(-20999, 'The price can''t be below ' || to_char(:new.listprice));
      end if;
    end;
    /
    

    由于异常,执行此操作的事务必须回滚。

    有关如何创建触发器的语法和示例的更多详细信息,请参阅in the manual


    但是不需要触发器,检查约束将大大更有效(在 Oracle 和 SQL Server 中)

    create table product
    (
       standardcost number,
       listprice    number, 
       constraint check_price check (listprice < standardcost * 1.2)
    );
    

    【讨论】:

    • 你必须声明'new.standardcost'吗?
    • 知道了,忘记了 new.standardcost 之前的 :
    • @Sam:已更正,谢谢。但是你真的应该为此使用检查约束。整个触发器方法一开始是一个非常糟糕的主意(更不用说 SQL Server 触发器中的损坏逻辑了)
    • 我同意,我刚刚被告知要这样做,哈哈。感谢您的帮助和信息。
    • 触发器似乎正在向后运行。我用我的代码和示例表信息更新了我的帖子
    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 2019-04-02
    • 2013-08-09
    • 2015-04-03
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多