多行插入

时间:2016-08-11 09:20:57

标签: mysql triggers

我在数据库中有两个名为KistStatusLastKistStatus的表。后者将拥有所有最新的'值KistStatus

KistStatus有大约174.000条记录,LastKistStatus应该有大约9.500条记录。

如果我手动插入记录(手动逐个执行插入),LastKistStatus将被正确填充。但是如果我执行sql导出文件,触发器似乎就会被破坏。

触发器:

DROP TRIGGER IF EXISTS `KistStatusTrigger`;
DELIMITER //
CREATE TRIGGER `KistStatusTrigger` AFTER INSERT ON `KistStatus`
 FOR EACH ROW begin
       DECLARE id_exists Boolean;
       DECLARE time_exists Timestamp;

       -- Check LastKistStatus table
       SELECT 1, `Timestamp`
         INTO @id_exists, @time_exists
       FROM LastKistStatus
       WHERE LastKistStatus.idKist = NEW.idKist;

       IF @id_exists > 0
       THEN
            IF @time_exists <= NEW.Timestamp
            THEN
                UPDATE LastKistStatus SET `Timestamp` = NEW.Timestamp, `idPartij` = NEW.idPartij, `Actie` = NEW.Actie, `idTaak` = NEW.idTaak, `idBewaarplaats` = NEW.idBewaarplaats, `Rij` = NEW.Rij, `Stapel` = NEW.Stapel, `Hoogte`= NEW.Hoogte, `KnolAantal` = NEW.KnolAantal, `Gewicht` = NEW.Gewicht, `idGebruiker` = NEW.idGebruiker, `Laatste` = NEW.Laatste WHERE `idKist` = NEW.idKist;
            END IF;
        ELSE
            INSERT INTO LastKistStatus (`idKistStatus`, `idKist`, `Timestamp`, `idPartij`, `Actie`, `idTaak`, `idBewaarplaats`, `Rij`, `Stapel`, `Hoogte`, `KnolAantal`, `Gewicht`, `idGebruiker`, `Laatste` ) VALUES (NEW.idKistStatus, NEW.idKist, NEW.Timestamp, NEW.idPartij, NEW.Actie, NEW.idTaak, NEW.idBewaarplaats, NEW.Rij, NEW.Stapel, NEW.Hoogte, NEW.KnolAantal, NEW.Gewicht, NEW.idGebruiker, NEW.Laatste);
        END IF;
END
//
DELIMITER ;

插入命令(从命令行完成) mysql -u *** -p TTTDB < KistStatus.sql

KistStatus.sql有很多这样的行:

INSERT INTO `KistStatus` (`idKistStatus`, `idKist`, `Timestamp`, `idPartij`, `Actie`, `idTaak`, `idBewaarplaats`, `Rij`, `Stapel`, `Hoogte`, `KnolAantal`, `Gewicht`, `idGebruiker`, `Laatste`) VALUES
(1, 227862, '2015-09-04 14:15:29', 40, '3', 0, 260, 2060, 33980, 1, NULL, 0, 40, 1),
(21, 229522, '2015-09-04 14:15:29', 40, '3', 0, 260, 2060, 33980, 2, NULL, 0, 40, 1),
(1083, 51102, '2015-09-05 07:33:37', 80, '3', 0, 40, 440, 5060, 1, NULL, 0, 100, 1),
(1103, 51102, '2015-09-05 07:33:44', 80, '3', 0, 40, 440, 5060, 1, NULL, 0, 100, 2),
(1123, 51102, '2015-09-05 07:33:44', 80, '3', 0, 40, 440, 5060, 1, NULL, 0, 100, 1),
(1143, 22202, '2015-09-05 07:37:33', 80, '3', 0, 40, 420, 4820, 1, NULL, 0, 100, 1);

我也测试过它并插入每条记录,但这并没有改变任何东西(除了永远插入......)

播种我做错了什么?我的触发器有问题吗?从命令行插入时是否会正确触发?我现在没有想法

1 个答案:

答案 0 :(得分:3)

您的问题

MySQL有点混乱,有两种不同类型的变量:

  • 本地变量没有前缀 @),它们是强类型的,并且作用于已声明它们的存储程序块用DECLARE语句;以及

  • user variables前缀 @),它们是松散类型并且作用于会话范围。请注意,它们既不需要也不能声明 - 它们只是直接使用。

您声明名为id_existstime_exists本地变量,但此后使用名为@id_exists@time_exists用户变量 }。由于后者的范围限定为会话,因此他们在同一会话中的触发器的后续调用之间保留其值,因此,@id_exists设置为1后不会再插入任何记录。

显而易见的解决方案是在这种情况下不使用用户变量,而是坚持使用本地变量:即在整个触发器中删除@前缀。

更好的方法

  1. 减少数据重复

    除非确实需要,否则不要存储KistStatusLastKistStatus的每一列的副本 - 您只需存储(idKist, idKistStatus)并获取当需要时,基础记录。

    ALTER TABLE LastKistStatus
      DROP COLUMN Timestamp,
      DROP COLUMN idPartij,
      DROP COLUMN Actie,
      DROP COLUMN idTaak,
      DROP COLUMN idBewaarplaats,
      DROP COLUMN Rij,
      DROP COLUMN Stapel,
      DROP COLUMN Hoogte,
      DROP COLUMN KnolAantal,
      DROP COLUMN Gewicht,
      DROP COLUMN idGebruiker,
      DROP COLUMN Laatste;
    

    然后,每当您之前引用LastKistStatus时,您现在只需在其位置引用LastKistStatus NATURAL JOIN KistStatus并获得相同的结果。

  2. 了解INSERT ... ON DUPLICATE KEY UPDATE

    根据触发器中的逻辑,LastKistStatus似乎只会包含任何给定idKist的单个记录。通过在数据库中强制执行此约束,您可以做一些聪明的事情:

    ALTER TABLE LastKistStatus ADD UNIQUE KEY (idKist);
    

    我在这里添加UNIQUE KEY。但是,这很可能(而且应该)是表的PRIMARY KEY,它具有相同的行为(但考虑到它的特殊状态,它会更快一些)。

    现在,您可以将操作合并为一个,而不是测试记录是否已存在然后相应地插入或更新:

    INSERT INTO LastKistStatus
      (idKist, idKistStatus)
    VALUES
      (NEW.idKist, NEW.idKistStatus)
    ON DUPLICATE KEY UPDATE
      idKistStatus = NEW.idKistStatus;
    
  3. 观察LastKistStatus实际上只是Kist

    的属性

    我认为你有一张表Kist。您只需将idKistStatusLastKistStatus表移动到该表中,然后完全取消LastKistStatus表。

    ALTER TABLE Kist
      ADD COLUMN idKistStatus BIGINT UNSIGNED NULL DEFAULT NULL,
      ADD FOREIGN KEY (idKistStatus) REFERENCES KistStatus (idKistStatus);
    
    UPDATE Kist JOIN LastKistStatus USING (idKist)
    SET    Kist.idKistStatus = LastKistStatus.idKistStatus;
    
  4. 完全取消触发器和缓存

    通过查找KistStatus表格中的groupwise maximum,您可以找到最新状态,而无需保留LastKistStatus

    SELECT * FROM KistStatus NATURAL JOIN (
      SELECT idKist, MAX(Timestamp) AS Timestamp FROM KistStatus GROUP BY idKist
    ) t;
    

    如果索引超过(idKist, Timestamp)

    ,则可以使用此选项
    ALTER TABLE KistStatus ADD INDEX (idKist, Timestamp);
    

    但请注意,它将返回具有最大时间戳的每个组中的所有记录 - 如果您特别优先选择一个,则需要定义用于识别哪个的逻辑。

    您甚至可以创建一个视图,以获得与您从LastKistStatus获得的结果相同的结果:

    CREATE VIEW LastKistStatus AS
    SELECT * FROM KistStatus NATURAL JOIN (
      SELECT idKist, MAX(Timestamp) AS Timestamp FROM KistStatus GROUP BY idKist
    ) t;
    

    然后像以前一样使用它:

    SELECT * FROM LastKistStatus WHERE ...