在同一个表上插入的MySQL触发器不起作用

时间:2015-07-20 08:37:28

标签: mysql triggers

上周在SO和其他许多网站上花了之后,我还有两个案例,我仍然无法正确编写触发器/功能等。这是我第一次使用触发器进行实际项目。

以下是此示例的示例表。我正在研究像赛马里奥这样的优惠代码。

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:
代码+ 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;

然后我创建了一个函数(因为存储过程不返回消息)但是它不起作用,它始终是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;

如何在数据库中实现此场景中的check-before-insert?

案例2
我正在尝试创建一个事件触发器,该事件触发器会将优惠券的状态设置为非活动状态,以用于其终止日期到期的优惠券。我尝试了一个教程http://www.sitepoint.com/how-to-create-mysql-events/,但无法使它工作。 我使用PDO在简单的sql prepared语句中使用FROM_UNIXTIME(:EndsOn)保存数据库中的条目,而$Coupon[":EndsOn"] = $dateFactory->today()->addWeeks(4)->getTimestamp(); $ dateFactory是Carbon库的对象,它是PHP DateTime类的扩展。

任何人都可以给我代码或psudocode示例吗?

1 个答案:

答案 0 :(得分: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上有一个索引,这将很快。