| | 1 | = Automatic calculation of store rating from order reviews |
| | 2 | |
| | 3 | === Description |
| | 4 | This trigger automatically calculates and updates the rating of a store whenever a customer review is added, modified, or deleted. |
| | 5 | |
| | 6 | The store rating is calculated as the average of all ratings given to orders associated with that store. |
| | 7 | |
| | 8 | This ensures that the rating attribute in the STORE table always reflects the current customer reviews without requiring the application to manually recalculate it. |
| | 9 | |
| | 10 | ==== Tables involved |
| | 11 | - Store |
| | 12 | - Order |
| | 13 | - Review |
| | 14 | - for_store |
| | 15 | |
| | 16 | ==== Type of trigger |
| | 17 | - AFTER INSERT |
| | 18 | - AFTER UPDATE |
| | 19 | - AFTER DELETE |
| | 20 | Activated on the review table. |
| | 21 | |
| | 22 | ==== SQL Code |
| | 23 | {{{#!sql |
| | 24 | CREATE OR REPLACE FUNCTION update_store_rating() |
| | 25 | RETURNS TRIGGER |
| | 26 | LANGUAGE plpgsql |
| | 27 | AS $$ |
| | 28 | DECLARE |
| | 29 | v_order_num INT; |
| | 30 | v_store_id INT; |
| | 31 | BEGIN |
| | 32 | -- Determine which order was affected |
| | 33 | IF TG_OP = 'DELETE' THEN |
| | 34 | v_order_num := OLD.order_num; |
| | 35 | ELSE |
| | 36 | v_order_num := NEW.order_num; |
| | 37 | END IF; |
| | 38 | |
| | 39 | -- Find the store associated with the order |
| | 40 | SELECT fs.store_id |
| | 41 | INTO v_store_id |
| | 42 | FROM for_store fs |
| | 43 | JOIN "order" o |
| | 44 | ON o.order_num = v_order_num |
| | 45 | WHERE fs.request_num IS NOT NULL |
| | 46 | LIMIT 1; |
| | 47 | |
| | 48 | -- Update the store rating |
| | 49 | IF v_store_id IS NOT NULL THEN |
| | 50 | UPDATE store s |
| | 51 | SET rating = ( |
| | 52 | SELECT COALESCE(AVG(r.rating), 0) |
| | 53 | FROM review r |
| | 54 | JOIN "order" o |
| | 55 | ON o.order_num = r.order_num |
| | 56 | -- The exact relationship between orders and stores |
| | 57 | -- should be used here according to the final schema |
| | 58 | WHERE o.order_num IN ( |
| | 59 | SELECT i.order_num |
| | 60 | FROM includes i |
| | 61 | JOIN sells sl |
| | 62 | ON sl.code = i.code |
| | 63 | WHERE sl.store_id = v_store_id |
| | 64 | ) |
| | 65 | ) |
| | 66 | WHERE s.store_id = v_store_id; |
| | 67 | END IF; |
| | 68 | |
| | 69 | RETURN NULL; |
| | 70 | END; |
| | 71 | $$; |
| | 72 | |
| | 73 | |
| | 74 | CREATE TRIGGER trg_update_store_rating |
| | 75 | AFTER INSERT OR UPDATE OR DELETE |
| | 76 | ON review |
| | 77 | FOR EACH ROW |
| | 78 | EXECUTE FUNCTION update_store_rating(); |
| | 79 | |
| | 80 | }}} |
| | 81 | |
| | 82 | === Logic explanation |
| | 83 | |
| | 84 | Whenever a review is inserted, updated, or deleted, the trigger: |
| | 85 | |
| | 86 | **1.** Identifies the affected order_num. |
| | 87 | **2.** Determines which store is associated with the order. |
| | 88 | **3.** Finds all reviews belonging to orders associated with that store. |
| | 89 | **4.** Calculates the average review rating using AVG(). |
| | 90 | **5.** Updates the rating attribute of the corresponding STORE. |
| | 91 | |
| | 92 | COALESCE is used so that a store with no reviews receives a rating of 0 instead of NULL. |
| | 93 | |
| | 94 | === Reason for trigger |
| | 95 | |
| | 96 | This trigger is useful because: |
| | 97 | |
| | 98 | - Rating is a derived value. |
| | 99 | - The application should not have to manually recalculate store ratings. |
| | 100 | - Ratings remain consistent after reviews are inserted, modified, or removed. |
| | 101 | - It prevents outdated ratings from remaining in the STORE table. |