英文:
how to add a constraint that checks multiple rows of information?
问题
我需要创建一个CONSTRAINT
,用于检查多行数据,数量是不确定的。我看到CHECK
只能访问当前行内的数据,我还看到要解决这个问题,需要声明一个函数(或类似函数的东西)。
为了澄清:
CREATE TABLE IF NOT EXISTS `ownership`(
`owner_id` INT,
`property_id` INT,
`share` DECIMAL(5,4),
CONSTRAINT `chk_share` CHECK (`share` <= 1.0 AND `share` >= 0),
--CONSTRAINT
-- `share`应该表示物业所有者拥有的百分比
-- 我想添加一个约束,不允许所有具有相同property_id的ownership行的总和大于1。
PRIMARY KEY(`owner_id`, `property_id`),
CONSTRAINT `fk_owner`
FOREIGN KEY(`owner_id`)
REFERENCES `market`.`entity` (`entity_id`)
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT `fk_property`
FOREIGN KEY(`property_id`)
REFERENCES `market`.`entity` (`entity_id`)
ON UPDATE CASCADE
ON DELETE CASCADE
)
我没有在这个网站上找到这个问题的答案,所以我有礼貌地提出了这个问题。我使用MySQL Workbench。
英文:
I need to make a CONSTRAINT
that checks data on multiple rows, an indefinite amount of them.
I've seen that CHECK
can only reach data inside the current row, and I have also seen that to solve this problem you need to declare a function (or something that looks just like one).
For clarification:
CREATE TABLE IF NOT EXISTS `ownership`(
`owner_id` INT,
`property_id` INT,
`share` DECIMAL(5,4),
CONSTRAINT `chk_share` CHECK (`share` <= 1.0 AND `share` >= 0),
--CONSTRAINT
-- `share` should show the percentage of the property owner owns
-- I want to add a constraint that does not allow the sum of all
-- ownership rows with the same property_id be greater than 1.
PRIMARY KEY(`owner_id`, `property_id`),
CONSTRAINT `fk_owner`
FOREIGN KEY(`owner_id`)
REFERENCES `market`.`entity` (`entity_id`)
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT `fk_property`
FOREIGN KEY(`property_id`)
REFERENCES `market`.`entity` (`entity_id`)
ON UPDATE CASCADE
ON DELETE CASCADE
)
I did not find this question answered on this site, so I am asking politely.
I use MySQL Workbench.
答案1
得分: 0
以下是代码部分的翻译:
DELIMITER |
CREATE TRIGGER `tgr_share`
BEFORE INSERT
ON `market`.`ownership`
FOR EACH ROW
BEGIN
IF ( SELECT SUM(`share`) + NEW.`share`
FROM `market`.`ownership`
WHERE `property_id` = NEW.`property_id`
GROUP BY `property_id` > 1.0 )
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ownership total shares > 1';
END IF;
END;
|
DELIMITER ;
DELIMITER |
CREATE PROCEDURE `fn_share` (`new_share` DECIMAL(5,4), `new_property_id` INT)
BEGIN
IF ( SELECT SUM(`share`) + `new_share`
FROM `market`.`ownership`
WHERE `property_id` = `new_property_id`
GROUP BY `property_id` > 1.0)
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ownership total shares > 1';
END IF;
END;
|
DELIMITER ;
CREATE TRIGGER `tgr_share_insert`
BEFORE INSERT
ON `market`.`ownership`
FOR EACH ROW
CALL `fn_share`(NEW.`share`, NEW.`property_id`);
CREATE TRIGGER `tgr_share_update`
BEFORE UPDATE
ON `market`.`ownership`
FOR EACH ROW
CALL `fn_share`(NEW.`share`, NEW.`property_id`);
英文:
Like @Schwern said I used a trigger.
DELIMITER |
CREATE TRIGGER `tgr_share`
BEFORE INSERT
ON `market`.`ownership`
FOR EACH ROW
BEGIN
IF ( SELECT SUM(`share`) + NEW.`share`
FROM `market`.`ownership`
WHERE `property_id` = NEW.`property_id`
GROUP BY `property_id` > 1.0 )
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ownership total shares > 1';
END IF;
END;
|
DELIMITER ;
I tested it and it works as intended.
Since I needed to use it with both insert and update, the code bellow works even better:
DELIMITER |
CREATE PROCEDURE `fn_share` (`new_share` DECIMAL(5,4), `new_property_id` INT)
BEGIN
IF ( SELECT SUM(`share`) + `new_share`
FROM `market`.`ownership`
WHERE `property_id` = `new_property_id`
GROUP BY `property_id` > 1.0)
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ownership total shares > 1';
END IF;
END;
|
DELIMITER ;
CREATE TRIGGER `tgr_share_insert`
BEFORE INSERT
ON `market`.`ownership`
FOR EACH ROW
CALL `fn_share`(NEW.`share`, NEW.`property_id`);;
CREATE TRIGGER `tgr_share_update`
BEFORE UPDATE
ON `market`.`ownership`
FOR EACH ROW
CALL `fn_share`(NEW.`share`, NEW.`property_id`);;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论