set serveroutput on;declare procedure what_to_choose(true_today in boolean, true_always in boolean) is dynamic_data boolean; static_rules boolean; begin dynamic_data := true_today and not true_always; static_rules := not dynamic_data; dbms_output.put_line( 'When data is ' || case when dynamic_data then 'dynamic' else 'static' end || case when static_rules then ' and all rules are static' else ' and some rules are adaptible' end || ' then ' || case when static_rules and not dynamic_data then 'unqualified' else 'flexible' end || ' assertions are better'); end what_to_choose;begin what_to_choose(true_today => true, true_always => true); what_to_choose(true_today => true, true_always => false);end;/
In the previous post of this series (Temporal SQL Assertions II: Ignore Legacy Data) we took a typical enterprise approach to applying business rules only to current data in motion and considering older data to be ‘Legacy’ and not in scope for validation efforts due to changes in circumstances.
The merits of this approach were really that we no longer had to disable an assertion in order to perform some of the updates to the data landscape that provided context for the business rules that the assertion was supposed to validate. This was the shortcoming of the initial naive approach to validating customer loyalty discounts that we took in the first post of the series.
In this post we will begin the process of making the assertion truly effective dated by regarding the current customer loyalty status as a slowly changing dimension with effective periods tracking when each status was valid for a customer.
Without changes to customer loyalty discount minimums, this approach should validate the loyalty status that was actually in effect for the customer at the time the order was placed.
Because of the complexities involved with this approach, I will not yet attempt to make the customer loyalty discount itself effective dated. These will retain the legacy approach to effective dating by using a discount_updated date to make the assertion ignore orders placed prior to the applicable loyalty status being updated.
Getting Started
The scripts for all examples in this post are available in the practicalplsql repository on github at effective-dated-assertions-3. I will add direct links to script files when first referenced.
To work with assertions, you will need to use OCI databases or pull a container to access Oracle AI Database 26 release update 1. See the first article in this series for the compose.yaml file and setup scripts to work with an Oracle Free container.
The Use Case: Customer Loyalty Discounts Based On Effective Status
The company is implementing their new customer loyalty program with guaranteed minimum discounts on customer orders for each loyalty level achieved.
There will be several customer loyalty levels defined, each with a minimum order discount requirement: “New” customers have no minimum discounts, “Preferred” customers receive a 5% discount and “Elite” customers always get a 10% discount.
Customers will start as “New“, and then get upgraded to “Preferred” and “Elite” as they place more orders. When customers are upgraded, their older orders should still be validated at the status grade that the customer had when the order was placed.
Over time, the minimum required discounts for the various loyalty levels will be changed. Orders validated before these changes occur will be considered Legacy Orders and need not be validated again.
Rather than enforcing the loyalty discounts through application code, the company has decided to use the new SQL assertions feature in Oracle 26.1 to ensure that orders meet the minimum loyalty discounts for the customer.
The solution shoud not require disabling the assertion or enabling the assertion in a novalidate state.
Tables
The new data model consists of tables for loyalty, customers, customer_loyalty and orders. The loyalty table has a minimum discount for each loyalty status and a discount_updated date to indicate that the minimums have been changed. The customers table holds only the customer name. The orders table has each customer order with a discount level.
The customer_loyalty table is used to manage the loyalty status that is effective for the customer over time. There is an effective date and and expires date associated with each customer status record. When a customer status is updated, the previous record needs to be expired and the new record effective date is set to sysdate while the expires date remains null.
Each customer should only have one open ended status record that represents the currently effective loyalty status. By adding a virtual column to indicate the current row for each customer with a unique index, we are assured that each customer will only have one row without an expires date value. This could be achieved using an assertion, but the simplicity of a conditional unique constraint with the underlying index for performance in finding the current customer record makes it a better design choice.
The loyalty table will have a discount_updated column to track the last change to a discount minimum for a status. This part of the implementation is still part of the ‘legacy’ workaround from the previous approach and it will result in making the assertion bypass orders when the relevant status discount is updated after the order is placed. If all goes well with basing the customer status on effective date periods in this iteration I will try to eliminate this as well in the next iteration.
--apply legacy style solution to loyalty tablecreate table if not exists loyalty( status varchar2(10) constraint loyalty_pk primary key, discount_min number(5,4) default 0 not null, discount_updated date default sysdate not null)/--insert the discount minimum for each loyalty statusbegin insert into loyalty(status, discount_min) values ('New', 0), ('Preferred', .05), ('Elite', 0.10); commit;end;/create table if not exists customers( customer_name varchar2(10) constraint customers_pk primary key)/--make customer loyalty a slowly changing dimension--use a unique constraint on a virtual column to enforce a single active rowcreate table if not exists customer_loyalty( customer_name varchar2(10) constraint customer_loyalty_fk_customers references customers(customer_name), status varchar2(10) default 'New' constraint customer_loyalty_fk_loyalty references loyalty(status) not null, effective date default sysdate not null, expires date, constraint customer_loyalty_ck_dates check (effective < expires), constraint customer_loyalty_pk primary key (customer_name, effective), active#row as (nvl2(expires, null, customer_name)) virtual, constraint customer_loyalty_u_active#row unique (active#row) deferrable initially deferred)/create table if not exists orders( order_id integer generated always as identity constraint orders_pk primary key, customer_name varchar2(10) constraint orders_fk_customers references customers(customer_name) not null, discount number(5,4) default 0 not null, placed date default sysdate not null)/
The Assertion
To update the assertion from the previous approach, we just need to check that the order is placed while the customer loyalty status is effective in addition to checking the last updated date of the discount minimum in the loyalty table. The comparison checks that the order.placed is between customer_loyalty.effective and customer_loyalty.expires, unless the expires date is null. This could be rewritten as o.placed between c.effective and nvl(c.expires, o.placed).
create assertion if not exists loyalty_discount_applied check ( not exists ( select 'order discount invalid for effective customer loyalty status' from orders o, customer_loyalty c, loyalty s where o.customer_name = c.customer_name and c.status = s.status and o.discount < s.discount_min and o.placed >= c.effective and (c.expires is null or o.placed < c.expires) and o.placed >= s.discount_updated ))/
View for Reviewing Order Discounts: A Band Join
The view is getting a bit more sophisticated. We now have an indirect band join between the order and the relevant customer loyalty status. I think this is more properly part of the join condition, but for now I will put it into the where clause for clarity. By putting the band join condition in the where clause it is obvious that the query will join multiple customer_loyalty records per order row that need to be filtered based on the order placed date and the effective period of the status.
create or replace view review_order_discounts asselect c.customer_name, p.status, (100 * s.discount_min) || '%' as loyalty_discount , o.order_id , (100 * o.discount) || '%' as order_discount , case when s.discount_updated > o.placed then 'Legacy Order' when o.discount < s.discount_min then 'Insufficient' when o.discount = s.discount_min then 'Meets Minimum' else 'Exceeds Minimum' end as discount_valid , o.placed , p.effective , p.expires , s.discount_updatedfrom customers c join customer_loyalty p on c.customer_name = p.customer_name join loyalty s on p.status = s.status join orders o on c.customer_name = o.customer_name where o.placed >= p.effective and (p.expires is null or o.placed < p.expires)order by c.customer_name, o.order_id/
The Sales_API Package
The methods exposed by the api package that I am using to support unit testing remain the same. For the implementations, the update_customer_loyalty and add_customer methods make use the additional table for the effective customer_loyalty status. With these dates set, the assertion will enforce the discount minimum for the status that is in effect for the customer at the time of placing the order.
The update_loyalty_discount implementation sets the discount_updated date to sysdate for the loyalty minimum discount as in the last iteration.
create or replace package sales_apias procedure add_customer( p_customer_name in customers.customer_name%type, p_status in loyalty.status%type); procedure add_order( p_customer_name in customers.customer_name%type, p_discount in orders.discount%type); procedure update_customer_loyalty( p_customer_name in customers.customer_name%type, p_status in loyalty.status%type); procedure update_loyalty_discount( p_status in loyalty.status%type, p_discount_min in loyalty.discount_min%type); end sales_api;/--modify the package body to handle effective dated customer statuscreate or replace package body sales_apias... procedure add_customer( p_customer_name in customers.customer_name%type, p_status in loyalty.status%type) is l_info t_details := 'create customer ' || p_customer_name || ' with status ' || p_status; begin insert into customers(customer_name) values (p_customer_name); insert into customer_loyalty(customer_name, status) values (p_customer_name, p_status); commit; print_tx_state(l_info); exception when others then rollback; print_tx_state(l_info, false); end add_customer; ... procedure update_customer_loyalty( p_customer_name in customers.customer_name%type, p_status in loyalty.status%type) is l_info t_details := 'update customer ' || p_customer_name || ' status to ' || p_status; l_date date := sysdate; begin update customer_loyalty set expires = l_date where customer_name = p_customer_name and expires is null; insert into customer_loyalty(customer_name, status, effective) values (p_customer_name, p_status, l_date); commit; print_tx_state(l_info); exception when others then rollback; print_tx_state(l_info, false); end update_customer_loyalty;...end sales_api;/
Testing Customer Orders
The unit tests for creating customers and placing orders all work correctly. The assertion is still working as intended, accepting valid order discounts and rejecting orders with insufficient discounts for the customer’s status. Using the customer_loyalty table to manage the customer’s status as is an ‘effective’ solution when the customer status is first set.
begin dbms_output.put_line('#Create customer Nina, status New'); sales_api.add_customer('Nina', 'New'); dbms_output.put_line('#Place valid orders: Nina, New, [0, 0.05]'); sales_api.add_order('Nina', 0); sales_api.add_order('Nina', 0.05); dbms_output.put_line('#Create customer Prue, status Preferred'); sales_api.add_customer('Prue', 'Preferred'); dbms_output.put_line('#Place valid order: Prue, Preferred, 0.05'); sales_api.add_order('Prue', 0.05); dbms_output.put_line('#Create customer Liza, Elite'); sales_api.add_customer('Liza', 'Elite'); dbms_output.put_line('#Place valid orders: Liza, Elite, [0.10,0.11]'); sales_api.add_order('Liza', 0.10); sales_api.add_order('Liza', 0.11); dbms_output.put_line('#Place invalid order: Prue, Preferred, 0'); sales_api.add_order('Prue', 0); dbms_output.put_line('#Place invalid order: Liza, Elite, 0.05'); sales_api.add_order('Liza', 0.05);end;/#Create customer Nina, status Newcreate customer Nina with status New COMMITTED#Place valid orders: Nina, New, [0, 0.05]place order for customer Nina with 0% discount COMMITTEDplace order for customer Nina with 5% discount COMMITTED#Create customer Prue, status Preferredcreate customer Prue with status Preferred COMMITTED#Place valid order: Prue, Preferred, 0.05place order for customer Prue with 5% discount COMMITTED#Create customer Liza, Elitecreate customer Liza with status Elite COMMITTED#Place valid orders: Liza, Elite, [0.10,0.11]place order for customer Liza with 10% discount COMMITTEDplace order for customer Liza with 11% discount COMMITTED#Place invalid order: Prue, Preferred, 0place order for customer Prue with 0% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.#Place invalid order: Liza, Elite, 0.05place order for customer Liza with 5% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.
Testing Updates To Customer Status
The next challenge is seeing if the assertion uses the effective status periods to validate each order appropriately and maintain the validation state of orders over time. Updating the customer status will change the conditions to be used for validating future orders, but the conditions that orders were originally validated under will remain constant. Two upgrades to Nina’s status will show us if the assertion is working as designed.
exec dbms_session.sleep(5);begin dbms_output.put_line('#Upgrade Nina to Preferred status'); sales_api.update_customer_loyalty('Nina', 'Preferred'); dbms_output.put_line('#Place valid orders: Nina, Preferred, [0.05,0.05]'); sales_api.add_order('Nina', 0.05); sales_api.add_order('Nina', 0.05); dbms_output.put_line('#Place invalid order: Nina, Preferred, 0.01'); sales_api.add_order('Nina', 0.01); end;/exec dbms_session.sleep(5);begin dbms_output.put_line('#Upgrade Nina to Elite status'); sales_api.update_customer_loyalty('Nina', 'Elite'); dbms_output.put_line('#Place valid orders: Nina, Elite, [0.10,0.11]'); sales_api.add_order('Nina', 0.10); sales_api.add_order('Nina', 0.11); dbms_output.put_line('#Place invalid order: Nina, Elite, 0.05'); sales_api.add_order('Nina', 0.05);end;/#Upgrade Nina to Preferred statusupdate customer Nina status to Preferred COMMITTED#Place valid orders: Nina, Preferred, [0.05,0.05]place order for customer Nina with 5% discount COMMITTEDplace order for customer Nina with 5% discount COMMITTED#Place invalid order: Nina, Preferred, 0.01place order for customer Nina with 1% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.#Upgrade Nina to Elite statusupdate customer Nina status to Elite COMMITTED#Place valid orders: Nina, Elite, [0.10,0.11]place order for customer Nina with 10% discount COMMITTEDplace order for customer Nina with 11% discount COMMITTED#Place invalid order: Nina, Elite, 0.05place order for customer Nina with 5% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.
Review Orders After Updating Customer Status
Before performing the last test of updating the loyalty discount minimum, lets check the view to see how the valid orders look at this point.
select * from review_order_discounts/CUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 10% 4 10% Meets Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:07Liza Elite 10% 5 11% Exceeds Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:07Nina New 0% 1 0% Meets Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:13 2026-03-16 09:11:07Nina New 0% 2 5% Exceeds Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:13 2026-03-16 09:11:07Nina Preferred 5% 8 5% Meets Minimum 2026-03-16 09:11:13 2026-03-16 09:11:13 2026-03-16 09:11:18 2026-03-16 09:11:07Nina Preferred 5% 9 5% Meets Minimum 2026-03-16 09:11:13 2026-03-16 09:11:13 2026-03-16 09:11:18 2026-03-16 09:11:07Nina Elite 10% 11 10% Meets Minimum 2026-03-16 09:11:18 2026-03-16 09:11:18 2026-03-16 09:11:07Nina Elite 10% 12 11% Exceeds Minimum 2026-03-16 09:11:18 2026-03-16 09:11:18 2026-03-16 09:11:07Prue Preferred 5% 3 5% Meets Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:07
The required loyalty discount at each stage in Nina’s progress from New to Elite status is always less than the order discount for orders placed in that stage. This report shows that the assertion is still able to validate all orders in the system by using effective periods for applying status discount requirements.
Test Updates To Loyalty Discount Minimums
The final set of tests involves changing the discount minimum for Preferred and Elite loyalty status levels. These updates will make previous orders out of scope for the assertion because of the loyalty.discount_updated effective date.
After updating the discount minimums, we can place some orders to confirm that new orders are validated correctly.
begin dbms_output.put_line('#Change Preferred to 0.0625 minimum discount'); sales_api.update_loyalty_discount('Preferred', 0.0625); dbms_output.put_line('#Change Elite to 0.1125 minimum discount'); sales_api.update_loyalty_discount('Elite', 0.1125);end;/#Change Preferred to 0.0625 minimum discountupdate status Preferred to discount minimum 6.25% COMMITTED#Change Elite to 0.1125 minimum discountupdate status Elite to discount minimum 11.25% COMMITTED
The new discount requirements were set without errors and new orders are being validated correctly with the new minimums. Everything is working as designed. Looking at the results of the view will show which orders in the system are capable of being revalidated.
CUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 11.25% 4 10% Legacy Order 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:23Liza Elite 11.25% 5 11% Legacy Order 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:23Nina New 0% 1 0% Meets Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:13 2026-03-16 09:11:07Nina New 0% 2 5% Exceeds Minimum 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:13 2026-03-16 09:11:07Nina Preferred 6.25% 8 5% Legacy Order 2026-03-16 09:11:13 2026-03-16 09:11:13 2026-03-16 09:11:18 2026-03-16 09:11:23Nina Preferred 6.25% 9 5% Legacy Order 2026-03-16 09:11:13 2026-03-16 09:11:13 2026-03-16 09:11:18 2026-03-16 09:11:23Nina Elite 11.25% 11 10% Legacy Order 2026-03-16 09:11:18 2026-03-16 09:11:18 2026-03-16 09:11:23Nina Elite 11.25% 12 11% Legacy Order 2026-03-16 09:11:18 2026-03-16 09:11:18 2026-03-16 09:11:23Nina Elite 11.25% 16 12% Exceeds Minimum 2026-03-16 09:11:23 2026-03-16 09:11:18 2026-03-16 09:11:23Prue Preferred 6.25% 3 5% Legacy Order 2026-03-16 09:11:08 2026-03-16 09:11:08 2026-03-16 09:11:23Prue Preferred 6.25% 14 7% Exceeds Minimum 2026-03-16 09:11:23 2026-03-16 09:11:08 2026-03-16 09:11:23Prue Preferred 6.25% 15 6.5% Exceeds Minimum 2026-03-16 09:11:23 2026-03-16 09:11:08 2026-03-16 09:11:23
Just like the previous Ignore Legacy approach, orders which were validated on placement but no longer fall into scope of the assertion are marked as Legacy Orders. The discount_updated effective date makes these orders irrelevant to the current state of the status discounts for Preferred and Elite. The report is still not exactly showing a glowing success of the Customer Loyalty Discounts program.
Summary
In the summary of the previous post I said that the goal would be to make Customer Status and Loyalty Discount Minimum into Type 2 Slowly Changing Dimensions interacting appropriately with the business rules using assertions. We have accomplished that with the Customer Status in this iteration. Now the proof of concept is confirmed for using assertions with effectivity periods.
Leaving the Loyalty Discount Minimum using the discount_updated technique left the full solution only half implemented. This allowed us to see both approaches (Legacy Effective Dating and Effectivity Periods) in a single iteration for easy comparison. The Legacy Effective Dating technique is starting to look like a convenience used to keep the appearance of simplicity.
Based on what we have learned here, in the next post we can finalize the approach of using assertions to validate multiple convergent slowly changing dimensions!
TLDR;
run-example-3-plsql.sql (or run-example-3.sql.sql)
spool run-example-3-plsql-results.txtprompt running example with plsql api@example-3-01-tables.sql@example-3-02-assertion.sql@example-3-03-view.sql@example-3-04-package.sql@example-3-05-tests-plsql.sql@example-3-06-drop-all.sqlspool off
run-example-3-plsql-results.txt (or run-example-3-sql-results.txt)
running example with plsql apiTable LOYALTY created.PL/SQL procedure successfully completed.Table CUSTOMERS created.Table CUSTOMER_LOYALTY created.Table ORDERS created.Assertion LOYALTY_DISCOUNT_APPLIED created.View REVIEW_ORDER_DISCOUNTS created.Package SALES_API compiledPackage Body SALES_API compiled#Create customer Nina, status Newcreate customer Nina with status New COMMITTED#Place valid orders: Nina, New, [0, 0.05]place order for customer Nina with 0% discount COMMITTEDplace order for customer Nina with 5% discount COMMITTED#Create customer Prue, status Preferredcreate customer Prue with status Preferred COMMITTED#Place valid order: Prue, Preferred, 0.05place order for customer Prue with 5% discount COMMITTED#Create customer Liza, Elitecreate customer Liza with status Elite COMMITTED#Place valid orders: Liza, Elite, [0.10,0.11]place order for customer Liza with 10% discount COMMITTEDplace order for customer Liza with 11% discount COMMITTED#Place invalid order: Prue, Preferred, 0place order for customer Prue with 0% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.#Place invalid order: Liza, Elite, 0.05place order for customer Liza with 5% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.PL/SQL procedure successfully completed.all valid orders have discount minimum that matches customer statusCUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 10% 4 10% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Liza Elite 10% 5 11% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Nina New 0% 1 0% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Nina New 0% 2 5% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Prue Preferred 5% 3 5% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28PL/SQL procedure successfully completed.upgrading Nina to preferred customer status creates a new effective status period#Upgrade Nina to Preferred statusupdate customer Nina status to Preferred COMMITTED#Place valid orders: Nina, Preferred, [0.05,0.05]place order for customer Nina with 5% discount COMMITTEDplace order for customer Nina with 5% discount COMMITTED#Place invalid order: Nina, Preferred, 0.01place order for customer Nina with 1% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.PL/SQL procedure successfully completed.Nina's original orders still satisfy the assertion based on the status that was effective (New)Nina's new orders after status was upgraded to Preferred also satisfy the assertionCUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 10% 4 10% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Liza Elite 10% 5 11% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Nina New 0% 1 0% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina New 0% 2 5% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina Preferred 5% 8 5% Meets Minimum 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:28Nina Preferred 5% 9 5% Meets Minimum 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:28Prue Preferred 5% 3 5% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:287 rows selected. PL/SQL procedure successfully completed.#Upgrade Nina to Elite statusupdate customer Nina status to Elite COMMITTED#Place valid orders: Nina, Elite, [0.10,0.11]place order for customer Nina with 10% discount COMMITTEDplace order for customer Nina with 11% discount COMMITTED#Place invalid order: Nina, Elite, 0.05place order for customer Nina with 5% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.PL/SQL procedure successfully completed.Nina's status is updated to Elite, all earlier orders show valid discounts for the status that was effective when the orders were placedCUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 10% 4 10% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Liza Elite 10% 5 11% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:28Nina New 0% 1 0% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina New 0% 2 5% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina Preferred 5% 8 5% Meets Minimum 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:38 2026-03-16 10:26:28Nina Preferred 5% 9 5% Meets Minimum 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:38 2026-03-16 10:26:28Nina Elite 10% 11 10% Meets Minimum 2026-03-16 10:26:38 2026-03-16 10:26:38 2026-03-16 10:26:28Nina Elite 10% 12 11% Exceeds Minimum 2026-03-16 10:26:38 2026-03-16 10:26:38 2026-03-16 10:26:28Prue Preferred 5% 3 5% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:289 rows selected. changing loyalty discounts can be done with assertion enabled, existing data that violates the assertion is ignoredPL/SQL procedure successfully completed.#Change Preferred to 0.0625 minimum discountupdate status Preferred to discount minimum 6.25% COMMITTED#Change Elite to 0.1125 minimum discountupdate status Elite to discount minimum 11.25% COMMITTEDPL/SQL procedure successfully completed.#Place valid orders: Prue, Preferred [0.07, 0.065]place order for customer Prue with 7% discount COMMITTEDplace order for customer Prue with 6.5% discount COMMITTED#Place valid order: Nina, Elite, 0.12place order for customer Nina with 12% discount COMMITTED#Place invalid order: Prue, Preferred, 0.05place order for customer Prue with 5% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.#Place invalid order: Nina, Elite, 0.10place order for customer Nina with 10% discount ROLLED BACK ORA-08601: SQL assertion (PRACTICALPLSQL.LOYALTY_DISCOUNT_APPLIED) violated.PL/SQL procedure successfully completed.while new orders will be validated by the assertion, existing orders that would not meet the assertion are ignored (shown as Legacy Order)CUSTOMER_N STATUS LOYALTY_DISCOUNT ORDER_ID ORDER_DISCOUNT DISCOUNT_VALID PLACED EFFECTIVE EXPIRES DISCOUNT_UPDATED ---------- ---------- ------------------ ---------- ------------------ --------------- ------------------- ------------------- ------------------- -------------------Liza Elite 11.25% 4 10% Legacy Order 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:43Liza Elite 11.25% 5 11% Legacy Order 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:43Nina New 0% 1 0% Meets Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina New 0% 2 5% Exceeds Minimum 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:33 2026-03-16 10:26:28Nina Preferred 6.25% 8 5% Legacy Order 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:38 2026-03-16 10:26:43Nina Preferred 6.25% 9 5% Legacy Order 2026-03-16 10:26:33 2026-03-16 10:26:33 2026-03-16 10:26:38 2026-03-16 10:26:43Nina Elite 11.25% 11 10% Legacy Order 2026-03-16 10:26:38 2026-03-16 10:26:38 2026-03-16 10:26:43Nina Elite 11.25% 12 11% Legacy Order 2026-03-16 10:26:38 2026-03-16 10:26:38 2026-03-16 10:26:43Nina Elite 11.25% 16 12% Exceeds Minimum 2026-03-16 10:26:44 2026-03-16 10:26:38 2026-03-16 10:26:43Prue Preferred 6.25% 3 5% Legacy Order 2026-03-16 10:26:28 2026-03-16 10:26:28 2026-03-16 10:26:43Prue Preferred 6.25% 14 7% Exceeds Minimum 2026-03-16 10:26:44 2026-03-16 10:26:28 2026-03-16 10:26:43Prue Preferred 6.25% 15 6.5% Exceeds Minimum 2026-03-16 10:26:44 2026-03-16 10:26:28 2026-03-16 10:26:4312 rows selected. drop all objectsView REVIEW_ORDER_DISCOUNTS dropped.Package SALES_API dropped.Assertion LOYALTY_DISCOUNT_APPLIED dropped.Table ORDERS dropped.Table CUSTOMER_LOYALTY dropped.Table CUSTOMERS dropped.Table LOYALTY dropped.
–Anthony Harper
Leave a comment