我遇到了一个问题,由于触发器的编写方式,无法在具有触发器的MySQL表上插入新记录。我得到错误:
Cardinality violation: 1241 Operand should contain 1 column(s)
它本质上是一个审计触发器,将新记录复制到包含额外数据的审计表中。我已经成功地证明了这个问题是特定于嵌套的“SELECT a.*…”的在触发器的Insert的VALUES()部分,因为当我用“NEW”的逐项列表替换该SELECT时。“xyx”列它工作正常。示例如下:
表A:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`email` varchar(50) NOT NULL,
`admin` tinyint(1) NOT NULL DEFAULT 0,
`date_updated` datetime NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
表B:
CREATE TABLE `users_audit` (
`action` varchar(8) NOT NULL,
`revision` int(11) NOT NULL,
`id` int(11) NOT NULL,
`username` varchar(20) NOT NULL,
`email` varchar(50) NOT NULL,
`admin` tinyint(1) NOT NULL,
`date_updated` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
触发器(在插入到表A时导致基数冲突):
CREATE TRIGGER users_ins AFTER INSERT ON users
FOR EACH ROW BEGIN
INSERT INTO users_audit
VALUES ('insert',
(SELECT IFNULL(MAX(a.revision), 0) + 1 FROM users_audit a where a.id = NEW.id),
(SELECT b.* FROM users b WHERE b.id = NEW.id LIMIT 1)
);
END
问题在于线路
(SELECT b.* FROM user_accounts b WHERE b.id = NEW.id LIMIT 1)
. 此上方的行没有问题(第一个“select”语句)。我甚至添加了“LIMIT 1”以确保只返回了1行(应该这样做,因为“id”是“users”上的PK)。我认为发生错误是因为第二条SELECT语句返回多个列(由于“SELECT b.*…”),并且它们不能以逗号分隔,以便“VALUES”中的项数与“users\u audit”中的列数匹配。
CREATE TRIGGER users_ins AFTER INSERT ON users
FOR EACH ROW BEGIN
INSERT INTO users_audit
VALUES ('insert',
(SELECT IFNULL(MAX(a.revision), 0) + 1 FROM users_audit a where a.id = NEW.id),
SELECT b.* FROM users b WHERE b.id = NEW.id LIMIT 1
);
END
但这在myPhpAdmin中甚至没有运行(我得到了一个语法错误)。
真的没有办法做到这一点,而不必手动写出每一列吗?作为记录,我已经完成了以下工作,但对于我要添加审计的所有表来说,这将需要很多额外的时间(必须手动写出它们的每一列)。
工作触发器,但过于冗长,必须单独列出新列:
CREATE TRIGGER users_ins AFTER INSERT ON users
FOR EACH ROW BEGIN
INSERT INTO users_audit
VALUES ('insert',
(SELECT IFNULL(MAX(a.revision), 0) + 1 FROM users_audit a where a.id = NEW.id),
NEW.id, NEW.username, NEW.email, NEW.admin, NEW.date_updated
);
END
我真的不想这样写专栏。当然,一定有什么方法可以实现我想要的?谢谢你的帮助!