как сделать так, чтобы вставка происходила только один раз в цикле курсора в mysql

#mysql #mysql-workbench

Вопрос:

Эта процедура берет название бренда, сопоставляет его с названиями брендов в таблице продуктов и создает кампанию. Когда я вызываю эту процедуру BrandNameCampaign с вводом имени бренда, которого НЕТ в таблице продуктов, она все еще создает кампанию. Я знаю, что это потому, что я сохранил запрос вставки вне цикла, где он проверяет, имеет ли курсор camp_c нулевые значения или нет. Однако, если я помещу запрос в цикл повтора курсора, он выдаст код ошибки: 1062 повторяющаяся запись » x «(x-это int) для кампании «ключ».ПЕРВИЧНЫЙ».

Как исправить свой код, чтобы новая кампания не вставлялась в таблицу без создания/запуска триггера? Я хочу, чтобы это работало в рамках этой процедуры.

Код таблицы

 create table Product (  ProductID int not null,  ProductType varchar (20) not null,  PackageType varchar(20) not null,   YearProduced int not null,  Price float not null,  Brand varchar(255) not null,  PRIMARY KEY (ProductID) )   create table Campaign (  CampaignID int not null,  CampaignStartDate date not null,  CampaignEndDate date,  PRIMARY KEY (CampaignID) )  create table DiscountDetails (  ProductID int not null,  CampaignID int not null,  MembershipLevel varchar(20) not null,   Discount int not null,  primary key (ProductID, CampaignID, MembershipLevel),  foreign key (ProductID) references Product (ProductID),  foreign key (CampaignID) references Campaign (CampaignID) )   

Процессуальный кодекс

 create procedure BrandNameCampaign (in brandname varchar(50))  begin  declare v_finished int default 0;  declare prod_id int;  declare newcampid int;  declare camp_brand varchar(255);  declare camp_c cursor for  select productid, brand  from product  where brandname = brand  order by price desc limit 5;    declare continue handler for not found set v_finished = 1;    SELECT   MAX(CampaignID)  INTO newcampid FROM  campaign;  set newcampid = 1   newcampid;     insert into `Campaign`(`CampaignID`,`CampaignStartDate`,`CampaignEndDate`) values   (newcampid,date_add(curdate(), interval 4 week), date_add( curdate(), interval 8 week));    -- working with cursor  open camp_c;  repeat  fetch camp_c into prod_id, camp_brand;  if not (v_finished = 1) then  insert into discountdetails values (prod_id, newcampid, 'S', 20);  insert into discountdetails values (prod_id, newcampid, 'G', 30);  insert into discountdetails values (prod_id, newcampid, 'P', 40);  end if;  until v_finished  end repeat;  close camp_c;  end//  

Ответ №1:

Одним из решений было бы использовать:

 insert ignore into `Campaign` ...  

ignore Средства не генерируют ошибку, если вставка приводит к дубликату ключа или другому типу ошибки.

Другим решением может быть использование логической переменной:

 declare v_do_insert tinyint(1) default true;  ...  repeat  insert into `Campaign`(`CampaignID`,`CampaignStartDate`,`CampaignEndDate`)   select newcampid, date_add(curdate(), interval 4 week), date_add( curdate(), interval 8 week)  from dual where v_do_insert=true;   set v_do_insert = false;   ... until v_finished end repeat;   

В этом примере значение insert...select будет вставлять одну строку в первый раз через цикл, но затем на последующих итерациях цикла v_do_insert теперь равно false, поэтому insert...select будет вставляться ноль строк.

Комментарии:

1. оба варианта работают, хотя я чувствую, что последний более безопасен, чем вариант игнорировать. Можете ли вы высказать некоторые соображения относительно опции игнорировать.

2. Один из недостатков ignore заключается в том, что он игнорирует другие типы ошибок, кроме повторяющихся ключей.