2011-05-09 42 views
9

我有两个表concept_access和concept_access_log。我想创建一个触发器,每次从concept_access删除一些东西,检查日志表中是否有类似的记录,如果没有,在从concept_access删除之前插入新记录。在concept_access如果触发器不存在

DROP TRIGGER IF EXISTS before_delete_concept_access; 
DELIMITER // 
CREATE TRIGGER before_delete_concept_access 
    BEFORE DELETE ON `concept_access` FOR EACH ROW 
    BEGIN 
     IF (SELECT 1 FROM concept_access_log WHERE map=OLD.map 
          AND accesstype=OLD.accesstype AND startdate=OLD.startdate AND stopdate=OLD.stopdate) IS NULL THEN 
      INSERT INTO concept_access_log (map, accesstype, startdate, stopdate) 
      VALUES (OLD.map, OLD.accesstype, OLD.startdate, OLD.stopdate); 
     END IF; 
    END// 
DELIMITER ; 

采样数据之前删除:

我修改的触发,现在它看起来像这样

map accesstype startdate stopdate 
1 public  NULL  NULL  
1 loggedin 2011-05-11 NULL  
1 friends  NULL  NULL  

日志表已经有前两排。它们与concept_access中的完全相同。当我从concept_access表中删除第一行,我得到这个日志表:

map accesstype startdate stopdate 
1 public  NULL  NULL  
1 loggedin 2011-05-11 NULL  
1 friends  NULL  NULL  
1 public  NULL  NULL  

虽然人们不应该因为(1,公共,NULL,NULL)已经存在有插入任何东西。

此表没有主键。我没有创建结构,所以不要问我为什么。改变它会破坏很多已经存在的功能。我只需要记录从表concept_access中删除的内容并将其存储在日志中而不重复。

我真的很感激,如果任何人都可以找出问题所在。

+0

OK,我想通了什么问题是,但仍然找不到合适的解决方案。有些字段可以为NULL,如果OLD值等于null,则执行像'accesstype = OLD.accesstype'这样的操作将不起作用。我试图将其更改为'(accesstype = OLD.accesstype OR OLD.accesstype IS NULL)',但仍然没有运气...... – Jull 2011-05-10 01:10:35

+0

您能否向我们展示整个已修改的触发器以及“concept_access”中的示例数据以及删除前后日志表中的记录? – pilcrow 2011-05-10 02:41:18

+0

@pilcrow:更新是在问题的主体 – Jull 2011-05-10 04:32:54

回答

13
DROP TRIGGER IF EXISTS before_delete_concept_access; 
DELIMITER // 
CREATE TRIGGER before_delete_concept_access 
    BEFORE DELETE ON `concept_access` FOR EACH ROW 
    BEGIN 
     IF (SELECT COUNT(*) FROM concept_access_log WHERE map=OLD.map 
          AND accesstype=OLD.accesstype AND startdate=OLD.startdate AND stopdate=OLD.stopdate) = 0 THEN 
      INSERT INTO concept_access_log (map, accesstype, startdate, stopdate) 
      VALUES (OLD.map, OLD.accesstype, OLD.startdate, OLD.stopdate); 
     END IF; 
    END// 
DELIMITER ; 

我不使用不存在,只是测试是否匹配计数大于0

你的代码运行良好,我matchine,什么是你的MySQL版本还大吗?

mysql> select version(); 
+------------+ 
| version() | 
+------------+ 
| 5.1.56-log | 
+------------+ 
1 row in set (0.00 sec) 
+0

版本5.1.54-1ubuntu4 – Jull 2011-05-10 04:51:51

+0

哇!它现在有效!非常感谢! – Jull 2011-05-10 04:57:31

+0

@Jull,你在使用Neo发布的_exact_触发器吗?在我的测试中,这个答案不能正确处理NULL,就像你在回应上面自己的问题时所评论的那样... – pilcrow 2011-05-10 16:49:03

1

修改子查询的WHERE子句中的每个条件检查值等价或值空:
(map = OLD.map OR COALESCE(map, OLD.map) IS NULL)
AND
(accesstype = OLD.accesstype OR COALESCE(accesstype, OLD.accesstype) IS NULL)
AND

等等等等

+0

我认为第二个选项将不起作用。我发现MySQL不会将NULL值视为相等。因此,唯一约束不适用于具有NULL值的行。 [链接](HTTP://计算器。com/questions/2520894/mysql-unique-clustered-constraint-not-constraining-as-expected) – Jull 2011-05-10 22:27:06

+0

@Jull,right - 更新答案。 – pilcrow 2011-05-11 02:25:44