我在数据库中有两个名为KistStatus
和LastKistStatus
的表。后者将拥有所有最新的'值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);
我也测试过它并插入每条记录,但这并没有改变任何东西(除了永远插入......)
播种我做错了什么?我的触发器有问题吗?从命令行插入时是否会正确触发?我现在没有想法
答案 0 :(得分:3)
MySQL有点混乱,有两种不同类型的变量:
本地变量(没有前缀 @
),它们是强类型的,并且作用于已声明它们的存储程序块用DECLARE
语句;以及
user variables(前缀 @
),它们是松散类型并且作用于会话范围。请注意,它们既不需要也不能声明 - 它们只是直接使用。
您声明名为id_exists
和time_exists
的本地变量,但此后使用名为@id_exists
和@time_exists
的用户变量 }。由于后者的范围限定为会话,因此他们在同一会话中的触发器的后续调用之间保留其值,因此,@id_exists
设置为1
后不会再插入任何记录。
显而易见的解决方案是在这种情况下不使用用户变量,而是坚持使用本地变量:即在整个触发器中删除@
前缀。
除非确实需要,否则不要存储KistStatus
中LastKistStatus
的每一列的副本 - 您只需存储(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
并获得相同的结果。
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;
LastKistStatus
实际上只是Kist
我认为你有一张表Kist
。您只需将idKistStatus
从LastKistStatus
表移动到该表中,然后完全取消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;
通过查找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 ...