Oracle:计算并插入到其他表触发器/过程

Posted

技术标签:

【中文标题】Oracle:计算并插入到其他表触发器/过程【英文标题】:Oracle: calculating and inserting to other table trigger/procedure 【发布时间】:2012-11-19 20:48:51 【问题描述】:

我正在尝试计算一些值并将它们添加到另一个表中。

所以我有预订、治疗和发票。用户预订一些治疗,然后预订会话生成发票。我已经手动插入发票插入语句,只是尝试根据预订会话数填充计算值。附言。治疗价格在治疗表中。

SQL> SELECT * FROM INVOICE;

    INV_ID|INV_DATETIME                  |INV_SUBTOTAL|INV_DISCOUNT|  INV_TOTAL
----------|------------------------------|------------|------------|-----------
       100|14-NOV-12 09.40.06.918000     |        $.00|        $.00|       $.00
       101|18-MAR-12 10.03.00.000000     |        $.00|        $.00|       $.00
       102|18-MAR-12 10.15.00.000000     |        $.00|        $.00|       $.00
       103|18-MAR-12 10.55.00.000000     |        $.00|        $.00|       $.00
       104|18-MAR-12 10.38.00.000000     |        $.00|        $.00|       $.00
       105|12-JUN-12 15.15.00.000000     |        $.00|        $.00|       $.00
       106|06-AUG-12 12.13.00.000000     |        $.00|        $.00|       $.00
       107|04-MAY-12 09.15.00.000000     |        $.00|        $.00|       $.00
       108|29-NOV-12 13.16.00.000000     |        $.00|        $.00|       $.00
       109|18-MAR-12 10.37.00.000000     |        $.00|        $.00|       $.00
       110|21-MAR-12 11.26.00.000000     |        $.00|        $.00|       $.00
       111|24-APR-12 11.16.00.000000     |        $.00|        $.00|       $.00
       112|12-MAY-12 10.27.00.000000     |        $.00|        $.00|       $.00
       113|21-MAY-12 13.33.00.000000     |        $.00|        $.00|       $.00
       114|18-JAN-12 12.17.00.000000     |        $.00|        $.00|       $.00
       115|20-JUN-12 11.18.00.000000     |        $.00|        $.00|       $.00
       116|09-JUN-12 10.14.00.000000     |        $.00|        $.00|       $.00

所以我使用以下 sql 查询来计算发票的小计价格,因为可以一次预订多个预订会话,这些将出现在同一张发票 *..1

SQL> COLUMN total FORMAT $99,999.99
SQL> SELECT IV.INV_ID, SUM(TR.TR_PRICE) as Total
  2  FROM BOOKING_SESSION BS, TREATMENT TR, INVOICE IV
  3  WHERE BS.INV_ID = IV.INV_ID
  4  AND BS.BK_TREATMENT = TR.TR_ID
  5  GROUP BY IV.INV_ID
  6  ORDER BY BS.INV_ID ASC;

    INV_ID|      TOTAL
----------|-----------
       100|    $605.00
       101|     $45.00
       102|     $70.00
       103|     $65.00
       104|     $50.00
       105|     $25.00
       106|     $25.00
       107|     $25.00
       108|     $25.00
       109|     $50.00
       110|     $25.00
       111|     $50.00
       112|     $15.00
       113|     $15.00
       114|     $25.00
       115|     $25.00
       116|     $25.00

现在我想获取每个值并将其添加到INV_SUBTOTAL

我尝试执行以下操作,但似乎不起作用。

CREATE OR REPLACE TRIGGER INV_SUBTOTAL
BEFORE INSERT OR UPDATE ON BOOKING_SESSION
FOR EACH ROW
BEGIN
   SELECT 
        (SELECT SUM(TR.TR_PRICE) FROM BOOKING_SESSION BS, TREATMENT TR, INVOICE IV WHERE BS.INV_ID = IV.INV_ID AND BS.BK_TREATMENT = TR.TR_ID)
      INTO :NEW.INV_SUBTOTAL
   FROM DUAL;
END;
/

警告:触发器创建时出现编译错误。

SQL> SHOW ERROR
Errors for TRIGGER INV_SUBTOTAL:

LINE/COL|ERROR
--------|-----------------------------------------------------------------
4/12    |PLS-00049: bad bind variable 'NEW.INV_SUBTOTAL'
SQL>

也许我做错了T_T

这是相关表的数据;

SQL> select * from treatment;

     TR_ID|TR_NAME             |TR_SPECIALIST|   TR_PRICE
----------|--------------------|-------------|-----------
         1|Hair removal        |            1|     $25.00
         2|Hair styling        |            1|     $50.00
         3|Nails               |            1|     $15.00
         4|Botox               |            1|     $30.00
         5|Make up             |            5|     $35.00
         6|Reflexology         |            3|     $25.00
         7|Massage therapy     |            3|     $25.00
         8|Facial care         |            4|     $25.00
         9|Weight loss         |            2|     $40.00
        10|Consultation        |            2|     $20.00

10 rows selected.

SQL> select * from booking_session
  2  where inv_id > 100;

     BK_ID|BK_DATE                       | BK_BOOKER|BK_CUSTOMER|BK_TREATMENT|START_SESSION              |END_SESSION              |STAFFAPPOINTED|   BK_ROOM|    INV_ID
----------|------------------------------|----------|-----------|------------|------------------------------|------------------------------|--------------|----------|----------
         4|18-MAR-12 10.35.00.000000     |         1|          4|          10|20-MAR-12 12.00.00.000000     |20-MAR-12 13.00.00.000000     |             1|         4|       109
         5|18-MAR-12 10.36.00.000000     |         1|          4|           4|21-MAR-12 11.00.00.000000     |20-MAR-12 12.00.00.000000     |             1|         5|       109
         6|18-MAR-12 10.50.00.000000     |         5|          5|           2|20-MAR-12 11.00.00.000000     |20-MAR-12 12.00.00.000000     |             5|         6|       103
        11|18-MAR-12 10.09.00.000000     |        10|         10|          10|20-MAR-12 11.00.00.000000     |20-MAR-12 12.00.00.000000     |            10|        10|       102
        12|18-MAR-12 10.12.00.000000     |        10|         10|           6|22-MAR-12 11.00.00.000000     |22-MAR-12 12.00.00.000000     |            11|        11|       102
        16|18-MAR-12 10.00.00.000000     |        15|         14|          10|20-MAR-12 11.00.00.000000     |20-MAR-12 12.00.00.000000     |            15|        14|       101
        17|18-MAR-12 10.02.00.000000     |        15|         14|           7|20-MAR-12 12.00.00.000000     |20-MAR-12 13.00.00.000000     |            16|        15|       101
        31|21-MAR-12 11.25.00.000000     |         1|          4|           1|24-MAR-12 11.00.00.000000     |24-MAR-12 12.00.00.000000     |             2|         1|       110
        32|24-APR-12 11.15.00.000000     |         1|          4|           2|26-APR-12 12.00.00.000000     |26-APR-12 13.00.00.000000     |             3|         2|       111
        33|12-MAY-12 10.25.00.000000     |         1|          4|           3|21-MAY-12 13.00.00.000000     |21-MAY-12 14.00.00.000000     |             4|         3|       112
        34|21-MAY-12 13.32.00.000000     |         1|          4|           3|26-MAY-12 15.00.00.000000     |26-MAY-12 16.00.00.000000     |             4|         3|       113
        35|18-JAN-12 12.14.00.000000     |         1|          4|           6|21-JAN-12 11.00.00.000000     |21-JAN-12 12.00.00.000000     |            17|         5|       114
        36|20-JUN-12 11.16.00.000000     |         1|          4|           7|25-JUN-12 11.00.00.000000     |25-JUN-12 12.00.00.000000     |            22|         5|       115
        37|09-JUN-12 10.12.00.000000     |         1|          4|           8|11-JUL-12 11.00.00.000000     |11-JUL-12 12.00.00.000000     |            24|         5|       116
        20|18-MAR-12 10.30.00.000000     |        15|         17|           7|20-MAR-12 09.00.00.000000     |20-MAR-12 10.00.00.000000     |            16|        17|       104
        39|18-MAR-12 10.35.00.000000     |         1|         17|           8|25-MAR-12 13.00.00.000000     |25-MAR-12 14.00.00.000000     |            24|         5|       104
        40|12-JUN-12 15.11.00.000000     |         1|         17|           8|11-JUL-12 11.00.00.000000     |11-JUL-12 12.00.00.000000     |            24|         5|       105
        41|06-AUG-12 12.13.00.000000     |         1|         17|           8|11-AUG-12 11.00.00.000000     |11-AUG-12 12.00.00.000000     |            24|         5|       106
        42|04-MAY-12 09.15.00.000000     |         1|         17|           8|28-JUN-12 11.00.00.000000     |28-JUN-12 12.00.00.000000     |            24|         5|       107
        43|29-NOV-12 13.16.00.000000     |         1|         17|           8|01-DEC-12 11.00.00.000000     |01-DEC-12 12.00.00.000000     |            24|         5|       108
        44|18-MAR-12 10.53.00.000000     |         5|          5|           3|20-MAR-12 13.00.00.000000     |20-MAR-12 14.00.00.000000     |             6|         7|       103
        38|18-MAR-12 10.13.00.000000     |         1|         10|           8|25-MAR-12 12.00.00.000000     |25-MAR-12 13.00.00.000000     |            24|         5|       102

这是与此问题相关的 ERD 的一点。

【问题讨论】:

【参考方案1】:

如果目标是使用在第二个查询中计算的TOTAL 更新特定INV_IDINVOICE 中的INV_SUBTOTAL 列,则需要UPDATE 语句。我的猜测(因为我不知道 TREATMENTBOOKING_SESSION 表是什么样子或者它们包含什么数据)是你想要一个看起来像这样的相关更新

UPDATE invoice inv
   SET inv_subtotal = (SELECT SUM(tr.tr_price)
                         FROM treatment tr,
                              booking_session bs
                        WHERE bs.inv_id = inv.inv_id
                          AND bs.bk_treatment = tr.tr_id)

BOOKING_SESSION 上的触发器不会执行任何操作,除非您实际更新(或插入)BOOKING_SESSION 表。通常,BOOKING_SESSION 上的行级触发器也不能在不生成 mutating table exception 的情况下查询 BOOKING_SESSION 表,我们几天前在您的一个问题中讨论了这一点。并且触发器中的:new 记录基于定义触发器的表——您只能引用属于BOOKING_SESSION 表的列。您不能引用 :new.inv_subtotal,除非 INV_SUBTOTAL 是您定义触发器的表中的列。

在现实世界中,这里也会存在严重的非规范化问题。将聚合数据与行级数据分开存储违反了基本规范化,并且几乎肯定会导致聚合数据与存储在TREATMENT 表中的较低级别数据不匹配的数据质量问题。由于这只是一项家庭作业,也许您的教授希望您忽略这个问题,但您希望在现实世界中对此非常敏感。

【讨论】:

嗨贾斯汀,好像我的老师从来没有提到过这类问题,你刚才提到的让我意识到我的数据库中的一个问题,如果治疗的价格发生变化,那么发票也会改变,这是一个问题,因为我们不想改变客户为历史目的和数据一致性实际支付的费用。那么我的问题是,计算发票的更好方法是什么? 由于应自动更新发票中的值,是否最好创建一个触发器,以便在进行或编辑新预订时插入/更新发票表中的记录? @JoseDavidGarciaLlanos - 在现实世界中,最好的方法取决于。通常,您根本不会将总数存储在任何地方。您将创建一个计算发票金额的函数(通过对 tr.tr_price 行求和)并使用它。如果您想存储发票金额,您将存储实际发送的发票金额,即使所有治疗的价格发生变化,您也希望保持不变。当然,这意味着您希望摘要和详细信息不同步。 @JoseDavidGarciaLlanos - 根据您需要维护的历史信息类型,您还可以为每个处理的每个发票捕获行项目,其中存储了服务时的处理价格,这将不会随着时间而改变。 谢谢贾斯汀,我刚刚意识到我可以对数据库进行一些不同的建模,如果我在 booking_sessiontreatment 之间有一个链接器表,然后只需调用链接器表处理会话并更改booking_session 到 booking,所以treatment_sessions 将包括在特定时间点预订的不同治疗,那么哪些表格将生成发票?链接器或预订表。

以上是关于Oracle:计算并插入到其他表触发器/过程的主要内容,如果未能解决你的问题,请参考以下文章

使用AFTER INSERT触发器将实体框架插入表中

触发器处理表更新

如何分离在 Oracle 中为特定表插入、更新和删除记录的过程

Oracle中的触发器是请求的一部分吗?

获取字符串,按分隔符拆分并插入到 Oracle 中的表过程 [重复]

在oracle中插入表B后创建触发器以将新行添加到表A中时出错