如何添加一个检查多行信息的约束?

huangapple go评论61阅读模式
英文:

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` &lt;= 1.0 AND `share` &gt;= 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` &gt; 1.0 ) 
		THEN 
			SIGNAL SQLSTATE &#39;45000&#39; SET MESSAGE_TEXT = &#39;ownership total shares &gt; 1&#39;;
		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` &gt; 1.0) 
		THEN 
			SIGNAL SQLSTATE &#39;45000&#39; SET MESSAGE_TEXT = &#39;ownership total shares &gt; 1&#39;;
		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`);;

huangapple
  • 本文由 发表于 2023年2月6日 04:07:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75355178.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定