我正在开发一个Yii2框架应用程序,在我的数据建模阶段,我决定让数据库引擎处理简单的更新并维护我的计数器表(用于返回未读消息的数量和用户的其他内容)。 / p>
我在消息表上设计了一个触发器,用于增加和减少用户的未读消息数。
用户可以是客户或建筑师。
数据库中的所有id列都是UNSIGNED INT(这些也是各个表的PK)。
从Workbench进行正向工程时遇到问题。我制作了一个包含测试数据的脚本,用于完整性测试和初始填充。在我为消息表添加AFTER_INSERT触发器之前,脚本执行正常。
这是触发器代码:
CREATE DEFINER = CURRENT_USER TRIGGER `visavis`.`message_AFTER_INSERT` AFTER INSERT ON `message` FOR EACH ROW
BEGIN
DECLARE archid INT UNSIGNED;
# Cheks if recevier is an architect
SELECT IFNULL(`visavis`.`architect`.`id`,0)
INTO archid
FROM `visavis`.`architect`
WHERE `visavis`.`architect`.`user` = NEW.`to`;
# Checks if the new message is set to sent (and not read)
IF NEW.status = 1
THEN
IF archid = 0 -- if the receiver is client
THEN
# Checks if the user receiving exists in the user_counter table
IF NOT EXISTS (SELECT 1 FROM `visavis`.`user_counter` WHERE `visavis`.`user_counter`.`user` = NEW.`to`)
THEN
# Insert new row into user_counter table
INSERT INTO `visavis`.`user_counter` (`user`,`messages`) VALUES (NEW.`to`,1);
ELSE
# Add one to the user followings counter
UPDATE `visavis`.`user_counter`
SET `visavis`.`user_counter`.`messages` = `visavis`.`user_counter`.`messages` + 1
WHERE `visavis`.`user_counter`.`user` = NEW.`to`;
END IF; -- if user_counter
ELSE
# Extra check if archid is null
#IF ISNULL(archid)
#THEN
# SET archid = 1; -- Testing value
#END IF;
# Checks if the architect receiving exists in the architect_counter table
IF NOT EXISTS (SELECT 1 FROM `visavis`.`architect_counter` WHERE `visavis`.`architect_counter`.`architect` = archid)
THEN
# Insert new row into architect_counter table
INSERT INTO `visavis`.`architect_counter` (`architect`,`messages`) VALUES (archid,1);
ELSE
# Add one to the user followings counter
UPDATE `visavis`.`architect_counter`
SET `visavis`.`architect_counter`.`messages` = `visavis`.`architect_counter`.`messages` + 1
WHERE `visavis`.`architect_counter`.`architect` = archid;
END IF; -- if architect_counter
END IF; -- if receiver is client
END IF; -- if message is sent
END
问题是我收到了这个错误:
ERROR: Error 1048: Column 'architect' cannot be null
在客户端或架构师检查的ELSE分支上面的代码中,我插入了额外的检查代码,以便为变量赋值(它被注释掉)。使用此代码脚本可以正常传递,但所有未读消息最终都会出现id = 1的架构师。
我也在添加表格'的DDL:
CREATE TABLE IF NOT EXISTS `architect` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'A PK for the table.',
`user` INT UNSIGNED NOT NULL COMMENT 'Link to the user that is the architect.',
`office` INT UNSIGNED NULL COMMENT 'Link to the architect\'s office, if any.',
`short_description` INT UNSIGNED NOT NULL COMMENT 'Link to the text of short description.',
`description` INT UNSIGNED NOT NULL COMMENT 'Link to the text of description.',
`specialty_1` INT UNSIGNED NULL COMMENT 'Link to the specialty.',
`specialty_2` INT UNSIGNED NULL COMMENT 'Link to the specialty.',
`specialty_3` INT UNSIGNED NULL COMMENT 'Link to the specialty.',
`order` INT UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_architect_specialty_1`
FOREIGN KEY (`specialty_1`)
REFERENCES `specialty` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_specialty_2`
FOREIGN KEY (`specialty_2`)
REFERENCES `specialty` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_specialty_3`
FOREIGN KEY (`specialty_3`)
REFERENCES `specialty` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_short_description`
FOREIGN KEY (`short_description`)
REFERENCES `text` (`id`)
ON DELETE RESTRICT
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_description`
FOREIGN KEY (`description`)
REFERENCES `text` (`id`)
ON DELETE RESTRICT
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_office`
FOREIGN KEY (`office`)
REFERENCES `office` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `fk_architect_user`
FOREIGN KEY (`user`)
REFERENCES `user` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = 'The info about the architect.';
CREATE TABLE IF NOT EXISTS `visavis`.`message` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'A PK of the table.',
`from` INT UNSIGNED NOT NULL COMMENT 'User that sent the message.',
`to` INT UNSIGNED NOT NULL COMMENT 'User that recieves the message.',
`text` VARCHAR(2000) NOT NULL COMMENT 'Text of the message. Length constrained in the frontend.',
`status` INT UNSIGNED NOT NULL DEFAULT 6 COMMENT 'Status of the message.',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date and time when the message was created. Automaticaly recieves status 6 (draft).',
`viewed_at` DATETIME NULL COMMENT 'Date and time when the message was viewed by the reciever. Set when the status changes to 1.',
`sent_at` DATETIME NULL COMMENT 'Date and time when the message was sent. Set when the status changes to 2.',
`replied_at` DATETIME NULL COMMENT 'Date and time when the message was replied, if any. Set when the status changes to 3.',
`shared_at` DATETIME NULL COMMENT 'Date and time when the message was shared to external board. Set when the status changes to 4.',
`deleted_at` DATETIME NULL COMMENT 'Date and time of message deletion (from the view). Set when the status changes to 5.',
`message_type` INT UNSIGNED NOT NULL COMMENT 'Link to the type of the message.',
`attachment` INT UNSIGNED NULL COMMENT 'Link to the attachment.',
`template` INT UNSIGNED NULL COMMENT 'Link to the template the message implements.',
PRIMARY KEY (`id`),
INDEX `fk_user_from_idx` (`from` ASC),
INDEX `fk_user_to_idx` (`to` ASC),
INDEX `fk_message_type_type_idx` (`message_type` ASC),
INDEX `fk_message_status_status_idx` (`status` ASC),
INDEX `fk_message_attachment_idx` (`attachment` ASC),
INDEX `fk_message_template_idx` (`template` ASC),
CONSTRAINT `fk_user_from`
FOREIGN KEY (`from`)
REFERENCES `visavis`.`user` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_user_to`
FOREIGN KEY (`to`)
REFERENCES `visavis`.`user` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_message_type_type`
FOREIGN KEY (`message_type`)
REFERENCES `visavis`.`message_type` (`id`)
ON DELETE RESTRICT
ON UPDATE NO ACTION,
CONSTRAINT `fk_message_status_status`
FOREIGN KEY (`status`)
REFERENCES `visavis`.`message_status` (`id`)
ON DELETE RESTRICT
ON UPDATE NO ACTION,
CONSTRAINT `fk_message_attachment`
FOREIGN KEY (`attachment`)
REFERENCES `visavis`.`attachment` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `fk_message_template`
FOREIGN KEY (`template`)
REFERENCES `visavis`.`message_template` (`id`)
ON DELETE SET NULL
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = 'Internal messaging system.'
CREATE TABLE IF NOT EXISTS `visavis`.`architect_counter` (
`architect` INT UNSIGNED NOT NULL COMMENT 'A PK of the table.',
`houses` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of houses in the system.',
`followers` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of followers.',
`liked_houses` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of houses that the users liked.',
`sold` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of purchased items of the architect.',
`messages` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of unread messages.',
`customizings` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of customize request an architect has received.',
`workings` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The number of customizing work an archotect has begun work on. (accepted and assigned quotes)',
PRIMARY KEY (`architect`),
CONSTRAINT `fk_architect_counter_architect`
FOREIGN KEY (`architect`)
REFERENCES `visavis`.`architect` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB
COMMENT = 'Counter table for summed values, of the logged in achitect, ' /* comment truncated */ /*needed for the front end.*/
我还尝试过COALESCE(),CASE,读取IFNULL()返回SIGNED值,以便我CAST()整个IFNULL子句。
我对分隔符(Workbench处理它们)没有任何问题
这是固定的:
IF EXISTS (SELECT 1 FROM `visavis`.`architect` WHERE `visavis`.`architect`.`user` = NEW.`to`)
THEN
SELECT `visavis`.`architect`.`id`
INTO archid
FROM `visavis`.`architect`
WHERE `visavis`.`architect`.`user` = NEW.`to`;
ELSE
SET archid = 0;
END IF;
答案 0 :(得分:1)
我可能会偏离此处,但此查询
SELECT IFNULL(`visavis`.`architect`.`id`,0)
INTO archid
FROM `visavis`.`architect`
WHERE `visavis`.`architect`.`user` = NEW.`to`;
会将archid
设置为select语句的结果行中的visavis.architect.id
的值,如果结果行中的值,则设置为0
为null
- 即null
中的id
值为visavis.architect
。
那么如果select语句没有匹配任何行,会发生什么?好吧,没有结果行,因此IFNULL
语句永远不会运行,而archid
仍保留null
的初始值。
我会删除ifnull
并将archid
设置为null。然后只需更新您的客户端/架构师检查以测试archid
是否为null:
SELECT `visavis`.`architect`.`id`
INTO archid
FROM `visavis`.`architect`
WHERE `visavis`.`architect`.`user` = NEW.`to`;
IF NEW.status = 1
THEN
IF ISNULL(archid) THEN -- if the receiver is client
...