相关表上的多行更新

时间:2012-01-14 07:53:10

标签: mysql triggers

我想在删除学生时使用触发器/程序更新表'Teacher'中多列'student_total'的行 更新相关表中的多行,多对多的实现 'n'老师可以有'''学生

  1. 有可能吗?因为它不可能存储 结果集(从您的网站获悉)
  2. 在Mysql,Postgress等?
  3. 感谢Adv

    Ritin

    --------------- SQL

    CREATE TABLE `Teacher` (
      `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(255) NOT NULL,
      `student_total` int(11) DEFAULT '0',
      PRIMARY KEY (`id`)
    );
    CREATE TABLE `Student` (
      `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(255) NOT NULL,
      PRIMARY KEY (`id`)
    );
    
    CREATE TABLE `Teacher_has_Student` (
      `teacher_id` smallint(5) unsigned NOT NULL,
      `student_id` smallint(5) unsigned NOT NULL,
      PRIMARY KEY (`teacher_id`,`student_id`),
      KEY `fk_Teacher_has_Student_teacher` (`teacher_id`),
      KEY `fk_breeder_has_breed_student` (`student_id`),
      CONSTRAINT `fk_Teacher_has_Student_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `Teacher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
      CONSTRAINT `fk_breeder_has_breed_student` FOREIGN KEY (`student_id`) REFERENCES `Student` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    );
    

    我有INSERT / DELETE / UPDATE的触发器 例如: ---------------------- SQL

    CREATE TRIGGER teacher__student_insert AFTER INSERT ON Teacher_has_Student 
    FOR EACH ROW 
    BEGIN
    UPDATE Teacher SET student_total = student_total + 1 WHERE id = NEW.teacher_id;
    END;
    

    下面的触发器只更新了1行,而目的是更新所有行。


    DELIMITER |
    CREATE TRIGGER my_student__delete AFTER DELETE ON Student 
    FOR EACH ROW 
    BEGIN
    set @std_id = old.id;
    UPDATE teacher SET student_total = student_total - 1 
    WHERE id = @std_id;
    END
    |
    

1 个答案:

答案 0 :(得分:0)

我认为你的第二次触发没有意义。在删除学生时,您将使用他的id并减少教师的student_total,该教师意外地与学生一样id

您的定义加上第一个触发器应该已经完成​​了这项工作。如果您删除了某个学生,则Teacher_has_Student会从CASCADE删除他的关系,并且DELETE您的触发器应该被触发以减少student_total受影响的老师。无论如何谷歌的一项简短研究显示,MySQL显然不会触发级联删除触发器:

http://bugs.mysql.com/bug.php?id=13102

可能的解决方法

您可以尝试修复第二个触发器以手动完成工作:

DELIMITER |
CREATE TRIGGER my_student__delete AFTER DELETE ON Student 
FOR EACH ROW 
BEGIN
    SET @std_id = old.`id`;
    UPDATE
        `Teacher` AS T
        INNER JOIN `Teacher_has_Student` AS TS ON T.`id`=TS.`teacher_id`
    SET `student_total` = `student_total` - 1 
    WHERE ST.`student_id` = @std_id;
END
|

但如果CASCADE上的FOREIGN KEY在触发前执行,那么这将无效。

可能更可靠的解决方法是放弃FOREIGN KEY定义并在TeacherStudent上创建触发器,以将删除和更新级联到Teacher_has_Student

将其标准化

通过这些变通办法,您必须记住许多不同的方案,以保持student_total有效。如果不一定要将student_total直接存储在教师表中,我建议强烈不要这样做。

信息绝对是多余的。保留约束和级联,但删除student_total列并删除所有触发器。然后使用JOIN获取学生编号:

SELECT
    T.`id`, T.`name`, COUNT(*) AS student_total
FROM `Teacher` AS T
    INNER JOIN `Teacher_has_Student` AS TS ON T.`id`=TS.`teacher_id`
GROUP BY T.`id`