Reputation: 144
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
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