如何在 Oracle Express 中创建触发器或过程以自动执行 table 列中的值

How to create trigger or procedure in Oracle express to automate values in a column of a table

如何在 line_total 列中输入帐户 (sales_line.line_total = product.unit_price * sales_line.line_qty) 生成的值?

我想要触发器或程序来自动执行此操作。当我在列中输入值时,它会自动触发触发器,进行计算并将结果插入列 sales_line.line_total.

我还想自动化列 sale.sale_total,它是值列 sales_line.line_total 的总和。你能为这两个问题做一个触发或程序吗?

你能帮帮我吗?

CREATE TABLE product (
    product_id    NUMBER(4) NOT NULL,
    category_id   NUMBER(4) NOT NULL,
    p_desc        VARCHAR2(40),
    cpu           VARCHAR2(14),
    ram           VARCHAR2(14),
    capacity      VARCHAR2(14),
    screen_size   VARCHAR2(14),
    battery       VARCHAR2(14),
    unit_price    NUMBER(7, 2),
    colour        VARCHAR2(14),
    qty_stock     NUMBER(4)
);
ALTER TABLE product ADD CONSTRAINT product_pk PRIMARY KEY ( product_id );

CREATE TABLE sale (
    sale_id       NUMBER(4) NOT NULL,
    sale_date     DATE,
    customer_id   NUMBER(4) NOT NULL,
    employee_id   NUMBER(4) NOT NULL,
    sale_total    NUMBER(7, 2)
);

ALTER TABLE sale ADD CONSTRAINT sale_pk PRIMARY KEY ( sale_id );

CREATE TABLE sales_line (
    sale_id      NUMBER(4) NOT NULL,
    product_id   NUMBER(4) NOT NULL,
    line_qty     NUMBER(4),
    line_total   NUMBER(7, 2)
);

ALTER TABLE sales_line ADD CONSTRAINT index_3 PRIMARY KEY ( sale_id,
                                                            product_id );

ALTER TABLE product
    ADD CONSTRAINT product_p_category_fk FOREIGN KEY ( category_id )
        REFERENCES p_category ( category_id );

ALTER TABLE sale
    ADD CONSTRAINT sale_customer_fk FOREIGN KEY ( customer_id )
        REFERENCES customer ( customer_id );

ALTER TABLE sale
    ADD CONSTRAINT sale_employee_id_fk FOREIGN KEY ( employee_id )
        REFERENCES employee ( employee_id );

ALTER TABLE sales_line
    ADD CONSTRAINT sales_line_product_fk FOREIGN KEY ( product_id )
        REFERENCES product ( product_id );

ALTER TABLE sales_line
    ADD CONSTRAINT sales_line_sale_fk FOREIGN KEY ( sale_id )
        REFERENCES sale ( sale_id );

以下是我到目前为止编写的触发器:

CREATE OR REPLACE TRIGGER trg_line_total_ai AFTER INSERT OR UPDATE ON sales_line
FOR EACH ROW
DECLARE
    lt_value NUMBER(7,2);
BEGIN
    SELECT product.unit_price INTO lt_value FROM product;
    UPDATE sales_line
    SET line_total = :NEW.line_qty * lt_value
   -- SET line_total = (line_qty * :NEW.unit_price)   
    WHERE product_id = :NEW.product_id;

    --UPDATE sales_line
      --  SET line_total = (line_qty * :OLD.unit_price)
        --WHERE product.product_id = :OLD.product_id;
END;


CREATE OR REPLACE TRIGGER trg_sale_total_ai AFTER INSERT OR UPDATE ON sales_line
FOR EACH ROW
BEGIN     
    UPDATE sale     
    SET sale_total = (sale_total + :NEW.line_total)   
    WHERE sale_id = :NEW.sale_id;

    UPDATE sale
        SET sale_total = (sale_total + :OLD.line_total)
        WHERE sale_id = :OLD.sale_id;
END;

要更新 sale_line,您必须使用前触发器,然后不需要在此 table 上进行更新。只给 :New.line_total 赋值。 要更新销售,您可以在 dame 触发器中进行。

请改用以下代码。请注意关键字 "Before" 而不是两个触发器定义中的 After

CREATE OR REPLACE TRIGGER trg_line_total_ai BEFORE INSERT OR UPDATE ON sales_line
    FOR EACH ROW
    DECLARE
        lt_value NUMBER(7,2);
    BEGIN
        SELECT product.unit_price INTO lt_value FROM product;
        UPDATE sales_line
        SET line_total = :NEW.line_qty * lt_value
       -- SET line_total = (line_qty * :NEW.unit_price)   
        WHERE product_id = :NEW.product_id;

        --UPDATE sales_line
          --  SET line_total = (line_qty * :OLD.unit_price)
            --WHERE product.product_id = :OLD.product_id;
    END;


    CREATE OR REPLACE TRIGGER trg_sale_total_ai BEFORE INSERT OR UPDATE ON sales_line
    FOR EACH ROW
    BEGIN     
        UPDATE sale     
        SET sale_total = (sale_total + :NEW.line_total)   
        WHERE sale_id = :NEW.sale_id;

        UPDATE sale
            SET sale_total = (sale_total + :OLD.line_total)
            WHERE sale_id = :OLD.sale_id;
    END;

你有两个主要问题。第一个(如其他答案中所述)是第一个触发器应该是 before 触发器,用于修改适当的记录。触发器的逻辑也可以简化(如下)

第二个问题是您应该减去 第二个触发器中的old 值。所以:

CREATE OR REPLACE TRIGGER trg_line_total_ai
    BEFORE INSERT OR UPDATE ON sales_line
FOR EACH ROW
BEGIN
    SELECT :NEW.line_qty * p.unit_price
    INTO :NEW.line_total
    FROM product p
    WHERE p.product_id = :NEW.product_id;
END;


CREATE OR REPLACE TRIGGER trg_sale_total_ai
    AFTER INSERT OR UPDATE ON sales_line
FOR EACH ROW
BEGIN     
    UPDATE sale     
        SET sale_total = (sale_total + :NEW.line_total)   
        WHERE sale_id = :NEW.sale_id;

    UPDATE sale
        SET sale_total = (sale_total - :OLD.line_total)
        WHERE sale_id = :OLD.sale_id;
END;

请注意,第二个触发器有两个更新。这允许更新 sale_id。如果您愿意,您可以将其包装到一个更新中:

    UPDATE sale     
        SET sale_total = (sale_total + 
                          (CASE WHEN sale_id = :NEW.sale_id THEN :NEW.line_total ELSE 0 END) -
                          (CASE WHEN sale_id = :OLD.sale_id THEN :OLD.line_total ELSE 0 END)
                         )  
        WHERE sale_id IN (:OLD.sale_id, :NEW.sale_id);

您在表达此逻辑时需要非常小心,以便它适用于更新和插入。您或许应该扩展此触发器以使其也适用于 deletes。