Assuming you create a materialized view log on Info
, you can create a materialized view that does a fast refresh on commit
CREATE MATERIALIZED VIEW mv_check_totals
REFRESH FAST
ON COMMIT
AS
SELECT personID,
sum( price ) total_price
FROM info
GROUP BY personID
HAVING sum( price ) > <<some constant>>
You can then create a constraint on this materialized view that will be violated if any rows appear in the materialized view
ALTER TABLE mv_check_totals
ADD CONSTRAINT constraint_name
CHECK( personID IS NULL )
With this in place, the total price will be checked at commit time. You'll be allowed to INSERT
as many rows as you'd like (after all, someone else could be deleting the existing rows in a separate session that will commit before you do). But you'll be stopped from committing the changes if they would violate your business rule. This is very much like the behavior you'd get with deferred constraints. But it does require a smarter application to recognize that a commit has failed and to alert the user to that fact rather than just reporting an error on a particular INSERT
.
In this implementation, I put the constant in the materialized view definition so that the materialized view will be empty if the business rule is satisfied. That avoids the cost of storing the total. You might want to omit the HAVING
clause and put the constant in your constraint, however. That would mean that you are storing extra data. But that makes it easier to change the constant in the future. And it materializes the total_price
for each person if that is something that you are going to be presenting on reports.