[英]Trigger isn't working / fired while multi-row inserting
I've two tables in the DB called KistStatus
and LastKistStatus
. 我在DB中有两个名为
KistStatus
和LastKistStatus
。 The latter will hold all the 'newest' values of KistStatus
. 后者将拥有
KistStatus
所有“最新”值。
KistStatus
has around 174.000 records, LastKistStatus
should have around 9.500 records. KistStatus
有大约174.000条记录, LastKistStatus
应该有大约9.500条记录。
If I insert the records by hand (execute the insert one by one by hand), the LastKistStatus
will be filled properly. 如果我手动插入记录(手动逐个执行插入),
LastKistStatus
将被正确填充。 But If I execute the sql export file, the trigger seems to be broken. 但是,如果我执行sql导出文件,触发器似乎被破坏了。
The trigger: 触发:
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 ;
Insert command (done from command line) mysql -u *** -p TTTDB < KistStatus.sql
插入命令(从命令行完成)
mysql -u *** -p TTTDB < KistStatus.sql
And the KistStatus.sql
have a lot of lines like this: 并且
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);
I also have tested it with and insert per record, but that didn't changed anything (other than taking forever to insert...) 我也测试了它并插入每条记录,但这没有改变任何东西(除了永远插入...)
Sow what am I doing wrong? 播种我做错了什么? Is there a problem in my trigger?
我的触发器有问题吗? Wouldn't it be triggered properly while inserting it from the command line?
从命令行插入时不会被正确触发吗? I'm out of ideas at the moment
我现在没有想法
MySQL, somewhat confusingly, has two different types of variable: MySQL有点混乱,有两种不同类型的变量:
local variables ( not prefixed by @
), which are strongly typed and scoped to the stored program block in which they have been declared with a DECLARE
statement; 局部变量 ( 不以
@
为前缀 ),它们是强类型的,并且作用于使用DECLARE
语句声明它们的存储程序块; and 和
user variables ( prefixed by @
), which are loosely typed and scoped to the session. 用户变量 ( 以
@
为前缀 ),它们被松散地键入并限定在会话中。 Note that they neither need nor can be declared—they are just used directly. 请注意,它们既不需要也不能声明 - 它们只是直接使用。
You declare local variables named id_exists
and time_exists
, but thereafter use user variables named @id_exists
and @time_exists
. 您声明了名为
id_exists
和time_exists
局部变量 ,但之后使用名为@id_exists
和@time_exists
用户变量 。 Since the latter are scoped to the session, they retain their values between subsequent invocations of the trigger within the same session—and, consequently, once @id_exists
has been set to 1
no further records will be inserted. 由于后者的范围限定为会话,因此它们在同一会话中的触发器的后续调用之间保留其值 - 因此,一旦将
@id_exists
设置为1
将不再插入其他记录。
The obvious solution is not to use user variables in this case, but instead to stick with your local variables: ie remove the @
prefixes throughout your trigger. 显而易见的解决方案是在这种情况下不使用用户变量,而是坚持使用本地变量:即在整个触发器中删除
@
前缀。
Unless you really need to, don't store a copy of every column from KistStatus
in LastKistStatus
—you can simply store (idKist, idKistStatus)
and fetch the underlying record as/when required. 除非您确实需要,否则不要在
LastKistStatus
存储KistStatus
中每一列的副本 - 您只需存储(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;
Then, whenever you referenced LastKistStatus
before, you can now simply reference LastKistStatus NATURAL JOIN KistStatus
in its place and get the same results. 然后,每当您之前引用
LastKistStatus
,您现在可以简单地在其位置引用LastKistStatus NATURAL JOIN KistStatus
并获得相同的结果。
INSERT ... ON DUPLICATE KEY UPDATE
. INSERT ... ON DUPLICATE KEY UPDATE
。 Given the logic in your trigger, it would appear that LastKistStatus
will only ever contain a single record with any given idKist
. 给定触发器中的逻辑,看起来
LastKistStatus
将只包含任何给定idKist
的单个记录。 By enforcing this constraint in the database, you can do some clever stuff: 通过在数据库中强制执行此约束,您可以执行一些聪明的操作:
ALTER TABLE LastKistStatus ADD UNIQUE KEY (idKist);
Here I'm adding a UNIQUE KEY
to the table. 在这里,我正在为表添加一个
UNIQUE KEY
。 However, it's quite probable that this could (and should) be the table's PRIMARY KEY
instead, which has the same behaviour (but is a bit faster, given its special status). 但是,很可能这(而且应该)是表的
PRIMARY KEY
,它具有相同的行为(但考虑到它的特殊状态,它会更快一些)。
Now, instead of testing whether a record already exists and then inserting or updating accordingly, you can combine the operations into one: 现在,您可以将操作合并为一个,而不是测试记录是否已存在然后相应地插入或更新:
INSERT INTO LastKistStatus (idKist, idKistStatus) VALUES (NEW.idKist, NEW.idKistStatus) ON DUPLICATE KEY UPDATE idKistStatus = NEW.idKistStatus;
LastKistStatus
is really just a property of Kist
LastKistStatus
实际上只是Kist
一个属性 I presume you have a table Kist
. 我猜你有一张桌子
Kist
。 You could simply move idKistStatus
from the LastKistStatus
table into that one, and do away with the LastKistStatus
table altogether. 您可以简单地将
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;
By finding the groupwise maximum from the KistStatus
table, you can locate the most recent status without maintaining LastKistStatus
at all: 通过从
KistStatus
表中查找KistStatus
最大值 ,您可以在不保留LastKistStatus
情况下找到最新状态:
SELECT * FROM KistStatus NATURAL JOIN ( SELECT idKist, MAX(Timestamp) AS Timestamp FROM KistStatus GROUP BY idKist ) t;
This would be sargable with an index over (idKist, Timestamp)
: 索引超过
(idKist, Timestamp)
可能会出现这种情况:
ALTER TABLE KistStatus ADD INDEX (idKist, Timestamp);
However, notice that it will return all records from each group that have the maximal timestamp—should you have a preference for one in particular, you will need to define the logic for identifying which. 但是,请注意它将返回具有最大时间戳的每个组中的所有记录 - 如果您特别优先选择一个,则需要定义用于标识哪个的逻辑。
You can even create a view to yield the same results as you used to obtain from LastKistStatus
: 您甚至可以创建一个视图,以产生与从
LastKistStatus
获取的结果相同的结果:
CREATE VIEW LastKistStatus AS SELECT * FROM KistStatus NATURAL JOIN ( SELECT idKist, MAX(Timestamp) AS Timestamp FROM KistStatus GROUP BY idKist ) t;
Then use it as before: 然后像以前一样使用它:
SELECT * FROM LastKistStatus WHERE ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.