Pruthvi Nag
Pruthvi Nag

Reputation: 144

How to assign a foreign key value using a a before insert trigger

I have a scenario like this:

There are two tables table1 and table2. The table1 has a primary key pkey and table2 has a foreign key fkey now during an insert if the foreign key is provided the value should be inserted as it is. Otherwise, it has to get a primary key from table1 using some computation and determine the foreign key to be inserted. How do i do this??

I am using MySql 5.0

EDIT

In my scenario, table1 holds the billing details, that is, the table1 has the bills and the total amount to be paid. The customer pays some amount of the total outstanding balance or will pay for a particular bill. What i want to do here is. When i am not provided with a bill_id (which is primary key in table1 and foreign key in table2) i would like to search for the oldest bill that is due in table1 and deduct the amount due and further deduct the remaining amount if any from the next bill in the billed order. I want to do this in the database layer rather than the upper layer. So when an insert is being done without a value for the foreign key the value should be retrieved and placed by the trigger or otherwise directly inserted. How do i achieve this?

Using the answers provided here, i tried this:

CREATE DEFINER=`root`@`localhost` TRIGGER `inflow_pay_done_insert` BEFORE INSERT ON `inflow_pay_done` FOR EACH ROW BEGIN
    DECLARE pkey INT;
    SET pkey = (SELECT bill_id from inflow_bills where payment_stat = 0 and rs_id = NEW.rs_id order by time_stamp limit 1);
    SET NEW.bill_id = IF(NEW.bill_id , NEW.bill_id , pkey);
    UPDATE raw_mat_sup rms SET rms.outstanding_bal_payable = rms.outstanding_bal_payable - NEW.amount where rms.rs_id = NEW.rs_id;
END|

and i am getting the following error when i am trying to insert in inflow_pay_done:

/* SQL Error (1048): Column 'bill_id' cannot be null */

Upvotes: 4

Views: 3357

Answers (1)

Kaii
Kaii

Reputation: 20540

you could use a subquery in the BEFORE INSERT trigger for this..

DELIMITER |
DROP TRIGGER `inflow_pay_done_insert`|
CREATE TRIGGER `inflow_pay_done_insert` BEFORE INSERT ON `inflow_pay_done`
FOR EACH ROW
BEGIN
  UPDATE raw_mat_sup rms 
    SET rms.outstanding_bal_payable = rms.outstanding_bal_payable - NEW.amount 
    WHERE rms.rs_id = NEW.rs_id;
  NEW.bill_id = IF(NEW.bill_id, 
    /* if "bill_id" is provided in INSERT statement, use provided value */
    NEW.bill_id, 
    /* if not, query other table for the correct value */
    (  /* this subquery is just an example, put your own query here*/
       SELECT bill_id FROM inflow_bills 
       /* find customers newest bill based on newest date and customer id */
       WHERE payment_stat = 0 AND rs_id = NEW.rs_id
       ORDER BY time_stamp DESC LIMIT 1
    )
  );
END;
|
delimiter;

UPDATE

Because of a MySQL Bug, this will only work when the column is allowed to be NULL and there is no constraint on the column (-> foreign key). The reason is that MySQL, unlike other DBMS, checks for constraints before a BEFORE INSERT trigger is executed and effectively avoids the execution of the trigger which would correct the data to insert.

The only solution for this, until the behaviour of MySQL changes, is to use a STORED PROCEDURE instead of plain INSERT. The stored procedure is then called with the values that should be inserted. In the procedure, the data correction (like in this case: selecting the right bill_id) is done and then INSERT is executed from within the stored procedure.

UPDATE II

This bug seems to be fixed in 5.7.1. Changelog says:

If a column is declared as NOT NULL, it is not permitted to insert NULL into the column or update it to NULL. However, this constraint was enforced even if there was a BEFORE INSERT (or BEFORE UPDATE trigger) that set the column to a non-NULL value. Now the constraint is checked at the end of the statement, per the SQL standard.

Upvotes: 4

Related Questions