2015-07-20 65 views
3

上周在SO和许多其他网站上花费了我的余额后,我仍然有两个仍然无法正确写入触发器/函数等的情况。这是我第一次工作在一个真实的项目上触发。MySQL触发插入同一张表不工作

下面是本示例的示例表。我正在提供像scenerio这样的代码。

CREATE TABLE IF NOT EXISTS `Demo` (
    `id` int(100) unsigned NOT NULL AUTO_INCREMENT, 
    `Code` varchar(25) NOT NULL, 
    `StoreID` int(100) unsigned NOT NULL, 
    `EndsOn` date DEFAULT NULL, 
    `Status` enum('Active','Inactive') NOT NULL DEFAULT 'Active', 
    PRIMARY KEY (`id`) 

); 

情况1:
A码+ STOREID是要约。使用相同的Code + StoreID只能有一个活动报价。因此,我无法在Code + Storeid + Status上设置复合唯一键,因为对不活动的商品没有限制。我只需要确保重复的有效报价不会发生。目前,我正在从PHP中进行1次转换来检查和另一次插入转换。
我试图在插入之前创建一个触发器,但事实证明我无法在同一个表上插入触发器。

CREATE TRIGGER `trig_no_dup` BEFORE INSERT ON `Demo` FOR EACH ROW 
    BEGIN 
     SET @Counter = (SELECT COUNT(*) FROM `Demo` WHERE `StoreID` = NEW.StoreID AND `Code` = NEW.Code AND `Status` = 'Active'); 
     IF @Counter = 0 THEN 
      INSERT INTO Demo (Code, StoreID) values (NEW.Code,NEW.StoreID); 
     ELSE 
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Hello, world! From Else Block'; 
     END IF; 
    END; 

然后我创建了一个功能(因为存储过程返回亘古不变的消息),但它不工作,它总是foing到if语句,决不会变成else子句。

CREATE FUNCTION `func_no_dup` (l_Code varchar(25), l_StoreID int(100)) RETURNS varchar(255) 
BEGIN  
    SET @Counter = (SELECT COUNT(*) FROM `Demo` WHERE `StoreID` = l_StoreID AND `Code` = l_StoreID AND `Status` = 'Active'); 
    IF @Counter = 0 THEN 
     RETURN 'OFFER DOES NOT EXISTS YET!!!!'; 
    ELSE 
     RETURN 'Offer is already active'; 
    END IF; 
END; 

如何在数据库的这个scenerio上实现check-before-insert?

案例2
我想创建一个事件触发将设置消费券的状态设置为无效的那些优惠券,其endson日到期。我尝试了一个教程http://www.sitepoint.com/how-to-create-mysql-events/,但无法使其工作。 我通过在使用PDO的简单sql准备语句中使用FROM_UNIXTIME(:EndsOn)来保存数据库中的条目,并且$Coupon[":EndsOn"] = $dateFactory->today()->addWeeks(4)->getTimestamp(); $ dateFactory是Carbon库的对象,它是PHP DateTime类的扩展。

任何人都可以给我代码或psudocode的例子,将工作?

回答

1

对于情况1你不应该做的插入,如果重复检测没有发现任何重复,正常的插入会做

CREATE TRIGGER `trig_no_dup` BEFORE INSERT ON `Demo` FOR EACH ROW 
    BEGIN 
     SET @Counter = (SELECT COUNT(*) FROM `Demo` WHERE `StoreID` = NEW.StoreID AND `Code` = NEW.Code AND `Status` = 'Active'); 
     -- if @Counter is 0 then just don't signal an error 
     IF @Counter != 0 THEN 
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Hello, world! From Else Block'; 
     END IF; 
    END; 

对于情况下2我认为这会工作

CREATE EVENT deleteOld 
ON SCHEDULE EVERY HOUR 
DO UPDATE demo SET status = 'Inactive' WHERE EndsOn < NOW(); 

请务必在EndsOn上有一个索引,这将很快。

+0

感谢案例1,它工作得很好。仍然在做一些更多的测试。案例2解决方案似乎没有工作。我确定了明天的日期。然后将系统日期更改为明天。它没有任何影响。事件sheduler处于活动状态。我确实将EndsOn NOW()更改为EndsOn