Как назначить значение внешнего ключа, используя триггер перед вставкой - PullRequest
4 голосов
/ 15 февраля 2012

У меня есть такой сценарий:

Есть две таблицы table1 и table2.table1 имеет первичный ключ pkey, а table2 имеет внешний ключ fkey теперь во время вставки, если предоставляется внешний ключ, значение должно быть вставлено как есть.В противном случае он должен получить первичный ключ из table1, используя некоторые вычисления, и определить внешний ключ для вставки.Как мне это сделать ??

Я использую MySql 5.0

РЕДАКТИРОВАТЬ

В моем сценарии table1 содержит платежные данные, которыеесть, table1 имеет счета и общую сумму, подлежащую оплате.Клиент платит некоторую сумму от общего непогашенного остатка или оплачивает определенный счет.Что я хочу сделать здесь.Когда мне не предоставляется bill_id (который является первичным ключом в table1 и внешним ключом в table2), я хотел бы найти самый старый счет, который должен быть в table1, и вычесть сумму, подлежащую оплате, и далеевычтите оставшуюся сумму, если таковая имеется, из следующего счета в выставленном заказе.Я хочу сделать это на уровне базы данных, а не на верхнем уровне.Поэтому, когда вставка выполняется без значения для внешнего ключа, значение должно быть извлечено и помещено триггером или иным образом непосредственно вставлено.Как мне этого добиться?

Используя ответы, приведенные здесь, я попробовал это:

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|

и получаю следующую ошибку при попытке вставить в inflow_pay_done:

/ * Ошибка SQL (1048): столбец bill_id не может быть пустым * /

1 Ответ

4 голосов
/ 15 февраля 2012

вы можете использовать подзапрос в триггере BEFORE INSERT для этого ..

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

Из-за MySQL Bug это будет работать только тогда, когда столбцу разрешено принимать значение NULL и нет ограничений на столбец (-> внешний ключ). Причина в том, что MySQL, в отличие от других СУБД, проверяет ограничения перед выполнением триггера BEFORE INSERT и эффективно избегает выполнения триггера, который исправил бы данные для вставки.

Единственное решение для этого, пока поведение MySQL не изменится, - это использовать STORED PROCEDURE вместо простого INSERT. Затем хранимая процедура вызывается со значениями, которые должны быть вставлены. В процедуре выполняется коррекция данных (как в этом случае: выбор правильного bill_id), а затем INSERT выполняется из хранимой процедуры.

ОБНОВЛЕНИЕ II

Эта ошибка исправлена ​​в 5.7.1. Список изменений говорит:

Если столбец объявлен как NOT NULL, вставка запрещена NULL в столбец или обновите его до NULL. Однако это ограничение был применен, даже если была ПЕРЕД вставкой (или ПЕРЕД ОБНОВЛЕНИЕМ) триггер), который устанавливает столбец в ненулевое значение. Теперь ограничение проверяется в конце оператора в соответствии со стандартом SQL.

...