Mysql # 1442 - Невозможно обновить таблицу 'stock' в сохраненной функции / триггере. - PullRequest
0 голосов
/ 11 апреля 2020

Мой тригер. Он работает нормально, но если я использую процедуру во вставке, я получаю сообщение об ошибке

1442 - Невозможно обновить таблицу 'stock' в сохраненной функции / триггере, потому что она уже используется оператором который вызвал эту сохраненную функцию / триггер.

bu, если я использую manuel insert в таблицу panier Нормальная вставка не показывает мне ошибку: '(

я использую это так:

call temps;
call stock_panier(94,19,'tranche');
call panier_ins(22547153,6185,null,now());

мой триггер:

DELIMITER $$
CREATE TRIGGER  Stock_cal BEFORE INSERT on panier
FOR EACH ROW  BEGIN
  DECLARE is_exist INT;
    DECLARE is_exist1 INT;
      DECLARE is_exist2 INT;
            set is_exist = (select stock.qte_res_s from stock WHERE stock.code_s=new.code_s);
        set is_exist1 = new.qte_p;
        set is_exist2 = new.qte_p;
            if  (is_exist<is_exist1) OR (is_exist2<1) THEN
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '✘: Opération a été refusée.';    
                ELSE  
       UPDATE stock SET qte_res_s=qte_res_s-new.qte_p,qte_sor_s=qte_sor_s+new.qte_p WHERE  new.code_s=stock.code_s  ;
       END if;

END$$
DELIMITER ; 

мой темперир стола:

CREATE PROCEDURE `temps`()
BEGIN
call virifier_table_exist('panier_tm');
if (@table_exists)=0 THEN
    CREATE TEMPORARY TABLE `panier_tm` (
      `N_p` bigint(20) DEFAULT Null,
      `N`   bigint(20) DEFAULT null,
        `Code_barr` varchar(100) DEFAULT NULL,
        `Référence` varchar(40) DEFAULT NULL,
        `Désignation` varchar(40) DEFAULT NULL,
        `Prix_HT` varchar(20) DEFAULT NULL,
        `Fournisseur` varchar(30) DEFAULT NULL,
        `Magasin` varchar(10) DEFAULT NULL,
        `Qte_Vent` varchar(5) DEFAULT NULL,
        `code_s` bigint(20) DEFAULT NULL,
        `code_d` bigint(20) DEFAULT NULL,
        tva_p varchar(5) DEFAULT Null,
        type_ver varchar(15) DEFAULT null);
SET @row_number:=0;
else    
DROP TEMPORARY TABLE `panier_tm`;
    CREATE TEMPORARY TABLE `panier_tm` (
      `N_p` bigint(20) DEFAULT Null,
      `N`   bigint(20) DEFAULT null,
        `Code_barr` varchar(100) DEFAULT NULL,
        `Référence` varchar(40) DEFAULT NULL,
        `Désignation` varchar(40) DEFAULT NULL,
        `Prix_HT` varchar(20) DEFAULT NULL,
        `Fournisseur` varchar(30) DEFAULT NULL,
        `Magasin` varchar(10) DEFAULT NULL,
        `Qte_Vent` varchar(5) DEFAULT NULL,
        `code_s` bigint(20) DEFAULT NULL,
        `code_d` bigint(20) DEFAULT NULL,
         tva_p varchar(5) DEFAULT Null,
        type_ver varchar(15) DEFAULT null);
SET @row_number:=0;
        end if;
END$$
DELIMITER ;

моя процедура:

drop PROCEDURE if EXISTS panier_ins ;
DELIMITER $$
CREATE PROCEDURE panier_ins (in code_cccp varchar(30), code_cl1 bigint(20),N_p1 bigint(20),dat date)
BEGIN
DECLARE code_faa varchar(20);
DECLARE  n_p2 bigint(20);
START TRANSACTION;
if (SELECT COUNT(Qte_Vent) from panier_tm tm2,stock WHERE tm2.code_s=stock.code_s and tm2.Qte_Vent>stock.qte_res_s and not EXISTS (select 1 from panier_vu vu2 where tm2.N_p=vu2.code_p and tm2.code_s=vu2.code_s ))>0 THEN 
SELECT "Veuillez vous assurer que le stock est terminé" AS message ;
ELSE 
set @count_n_p=(select COUNT(n_p) from panier_tm where n_p=n_p1);
set @n_p=(select n_p from panier_tm where n_p=n_p1);
       if (@n_p) is null OR  (@count_n_p)=0 THEN
     SET @n_p2=(SELECT MIN(t1.code_p+1) as id FROM panier t1 LEFT JOIN panier t2 On t1.code_p+1=t2.code_p Where t2.code_cl IS NULL);
           set @n_p2=if(@n_p2 = null,1,@n_p2);
           INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT @n_p2,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE    preduit.code_pr=stock.code_pr  and tm1.code_s=stock.code_s and  NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
    update panier_tm set N_p=@n_p2;
   set code_faa=(SELECT MIN(SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1) as id FROM facture t1 LEFT JOIN facture t2 On SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1=SUBSTRING(t2.code_fa, 6, length(t2.code_fa)-5) Where t2.code_fa IS NULL);
  set code_faa=  CONCAT( DATE_FORMAT(now(),"%Y"),"/",code_faa) ;
    INSERT INTO `facture`(`autot`, `code_fa`, `code_ccp`, `code_cl`, `code_p`, `date_fa`, `type_ver`) VALUES (null,code_faa,code_cccp,code_cl1,@n_p2,now(),typ);
   COMMIT ;
     ELSE
    START TRANSACTION;
           INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT tm1.n_p,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr and tm1.code_s=stock.code_s and  NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
         DELETE b FROM `panier` b LEFT JOIN panier_tm f ON  f.code_s = b.code_s and b.code_p=f.N_p WHERE code_p=n_p1 and f.N_p is null;
          UPDATE `panier` p1,panier_tm tms SET p1.`n_p`=tms.N_p,p1.`qte_p`=tms.Qte_Vent,p1.`prix_p`=tms.Prix_HT,`tva_p`=tva1 WHERE p1.code_p=N_p1 and p1.code_s=tms.code_s;
   COMMIT ;
     END if;
END IF;
END$$
DELIMITER ;

1 Ответ

0 голосов
/ 11 апреля 2020

Ваша проблема заключается в двух вставках в panier, которые зависят от stock, в то время как у вас есть on insert -триггер на panier, который изменяет таблицу stock, от которой вставка в panier зависит:

INSERT INTO `panier`(`code_p`, ...) SELECT @n_p2,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...

INSERT INTO `panier`(`code_p`, ...) SELECT tm1.n_p,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...

Они оба имеют структуру

INSERT INTO panier (...) SELECT ... FROM stock ...

, которая недопустима, если у вас есть триггер вставки на panier, который изменяет stock. Эти вставки являются оператором , который вызвал эту сохраненную функцию / триггер , в котором вы не можете обновить таблицу 'stock' . MySQL по техническим причинам не может этого сделать.

Прямой технический обходной путь для этого - создать временную таблицу, в которой вы сохраните результат вашего SELECT ..., а затем вставить в панель из эта временная таблица, например что-то вроде

 create temporary table tmp (...);
 insert into tmp (...) select ... from stock ...;
 insert into panier (...) select ... from tmp;
 drop table tmp;

Теперь триггер вставки больше не изменяет никаких зависимых таблиц, поскольку вы выбираете только из tmp.

В вашей процедуре это будет выглядеть как

 create temporary table tmp (code_p bigint(20), n_p bigint(20), 
 ..., tva_p varchar(5)); 

 if (@n_p) is null OR  (@count_n_p)=0 THEN  
   ...
   insert into tmp (code_p, n_p, ...) 
   SELECT @n_p2,tm1.n,stock.code_s, ...
   FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...

   insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
   ...
else  
   ...
   insert into tmp (code_p, n_p, ...) 
   SELECT tm1.n_p,tm1.n,stock.code_s, ...
   FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...

   insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
   ...
end if; 
drop table tmp;

Вы, конечно, можете создать временную таблицу в своей процедуре temps.

Также обычно возможно изменить дизайн вашей процедуры, триггеров или логики c так вам это не нужно, но это, вероятно, будет большим усилием.

И вы должны проверить, действительно ли это логика c, которую вы хотите применить, например, если вы хотите определить текущее состояние stock, какие строки вставлять, заморозьте это состояние (поместив его в tmp -таблицу) и затем запустите вставку независимо от того, как stock -таблица изменилась во время этих вставок (например, если бы вы вставили 2-ю строку, если бы знали, что изменилась первая строка в stock ). Я не проверял, что должен делать ваш код, так что это может или не может применяться здесь, а может и не быть проблемой здесь, но циклические зависимости (и ошибка, которую вы получаете здесь из-за этого) иногда могут быть знак для основной проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...