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_ID
中INVOICE
中的INV_SUBTOTAL
列,则需要UPDATE
语句。我的猜测(因为我不知道 TREATMENT
或 BOOKING_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_session
和 treatment
之间有一个链接器表,然后只需调用链接器表处理会话并更改booking_session 到 booking,所以treatment_sessions 将包括在特定时间点预订的不同治疗,那么哪些表格将生成发票?链接器或预订表。以上是关于Oracle:计算并插入到其他表触发器/过程的主要内容,如果未能解决你的问题,请参考以下文章
如何分离在 Oracle 中为特定表插入、更新和删除记录的过程