2012-11-09 57 views
4

所以之前我解释一下我的问题,这里有一些精简表定义来帮助说明我的问题:与动态值的MySql条件插入

-- Holds data about different memberships 
CREATE TABLE IF NOT EXISTS `Member_Types` ( 
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
`Name` VARCHAR(20) NOT NULL, 
`Description` VARCHAR(255) NOT NULL, 
`Member_Limit` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0', 
PRIMARY KEY(`ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 


INSERT INTO `Member_Types` (`ID`, `Name`, `Description`, `Member_Limit`) VALUES 
(1, 'General Member', 'Description of this membership.', 00), 
(2, 'Extended Member', 'Description of this membership.', 00), 
(3, 'Premium Member', 'Description of this membership.', 00), 
(4, 'General Administrator', 'Description of this membership.', 05), 
(5, 'Master Administrator', 'Description of this membership.', 01); 

-- Stores the basic data about our site members 
CREATE TABLE IF NOT EXISTS `Member_Infos` ( 
`ID` BIGINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT, 
`Username` VARCHAR(30) NOT NULL UNIQUE, 
`Password` CHAR(41) NOT NULL, 
`EmailAddr` VARCHAR(100) NOT NULL, 
`Type_ID` INT UNSIGNED NOT NULL, 
`Salt_ID` BIGINT(8) UNSIGNED ZEROFILL NOT NULL, 
PRIMARY KEY(`ID`), 
FOREIGN KEY(`Type_ID`) REFERENCES `Member_Types` (`ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

的Member_Infos表包含结合Member_Infos.Type_ID =外键Member_Types.ID

的Member_Types表具有列Member_Limit其包含表示所述Member_Infos表 可以包含的记录的最大数目,其中其TYPE_ID等于一个整数Member_Types.ID

我能写一个检查约束,但显然mysql不检查约束。 我想编写一个触发器,检查member_infos表中的记录数是否为< =插入前的Member_Types.Member_Limit。 例如:使用上面的数据,记录4的Member_Limit = 5。如果尝试将新记录插入到Member_Infos表中, 的Type_ID = 4,并且Member_Infos表中的记录数与Type_ID < = 5比数据被插入,否则被拒绝。 任何意见将不胜感激。

+0

我会说触发想法可能是最好的。 – Aatch

+0

高度赞赏的问题。希望答案也是:) – Sami

回答

2

代替触发器,您可以编写自己的普通查询以在插入前检查“约束”。尝试:

INSERT INTO member_infos 
SELECT  1, 'Timothy', 'secret', '[email protected]', 5, 0 
FROM  dual 
WHERE  (SELECT COUNT(*) FROM member_infos WHERE Type_ID = 5) 
      < 
      (SELECT Member_Limit FROM member_types WHERE ID = 5) 

我已经使用在Type_ID = 5这忽略如果计数标准不被满足,并插入仅当与类型ID member_info条目的构件的计数= 5小于极限情况,以检查设置在您的member_types表中

1

在MySQL中,触发可能是在数据库级别做的正确方法。

但是,强制执行这种业务规则通常被认为是您应该在应用程序层而不是数据库中执行的操作。业务规则有改变的习惯,修改应用层通常比数据库更容易。为应用层代码编写单元测试也更容易,调试应用层通常更容易。

0

Sql Fiddle Demo Link

您可以通过添加下面的INSERT语句

INSERT INTO `member_infos` (`ID`, `Username`, `Password`, `EmailAddr`, `Type_ID`, 
`Salt_ID`) VALUES (2, 'ewsew', 'ew', 'ewq', 2, 2); 

在这整个代码结束尝试。你不会被允许插入,因为type_id=2被允许0记录为member_ifos。相似的,在插入5个Reocr之后,您将在插入时出现错误type_id=5

我添加了一个触发器,因为您需要验证每个新条目而不是某个静态值。 所以它不是一样的问题,其中双可以工作像一些问题就像MySQL Conditional Insert因为你需要新的。TYPE_ID这是只有在触发器

以下可用的完整代码

CREATE TABLE IF NOT EXISTS `member_infos` (
    `ID` bigint(8) unsigned zerofill NOT NULL AUTO_INCREMENT, 
    `Username` varchar(30) NOT NULL, 
    `Password` char(41) NOT NULL, 
    `EmailAddr` varchar(100) NOT NULL, 
    `Type_ID` int(10) unsigned NOT NULL, 
    `Salt_ID` bigint(8) unsigned zerofill NOT NULL, 
    PRIMARY KEY (`ID`), 
    UNIQUE KEY `Username` (`Username`), 
    KEY `Type_ID` (`Type_ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; 

-- Triggers `member_infos` 

DROP TRIGGER IF EXISTS `validate_Member_infos_insert`; 
DELIMITER // 
CREATE TRIGGER `validate_Member_infos_insert` BEFORE INSERT ON `member_infos` 
FOR EACH ROW begin 
declare lim int;declare cnt int; 
select member_limit into lim from member_types where id=new.Type_id; 
select count(*) into cnt from Member_Infos where type_id=new.Type_id; 
if cnt>=lim 
then 
select `Member Limit exeeded for this type` into lim from member_infos; 
end if; 
end 
// 
DELIMITER ; 

CREATE TABLE IF NOT EXISTS `member_types` (
    `ID` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `Name` varchar(20) NOT NULL, 
    `Description` varchar(255) NOT NULL, 
    `Member_Limit` tinyint(2) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; 

INSERT INTO `member_types` (`ID`, `Name`, `Description`, `Member_Limit`) 
VALUES (1, 'General Member', 'Description of this membership.', 0), 
(2, 'Extended Member', 'Description of this membership.', 0), 
(3, 'Premium Member', 'Description of this membership.', 0), 
(4, 'General Administrato', 'Description of this membership.', 5), 
(5, 'Master Administrator', 'Description of this membership.', 1); 

INSERT INTO `member_infos` (`ID`, `Username`, `Password`, `EmailAddr`, 
`Type_ID`, `Salt_ID`) VALUES (1, 'ewsew', 'ew', 'ewq', 5, 2); 

注:有人可能会提高/删除错误信息#1054 - Unknown column 'Member Limit exeeded for this type' in 'field list'请。这个例外是必要的,因为它阻止了按照提交者所需条件插入。但改善将不胜感激。我无法整理出来。

+0

“注意:有些人可能会改善/删除错误消息#1054--请在'字段列表'中为此类型提供未知列'会员限制'。” ...事实上,引发错误的正确方法是使用SIGNAL语句,因为已经发布在另一个答案中。从我的角度来看,这篇文章提供了更多的实用代码和小提琴演示(很棒)的细节,但并没有解决根本问题。 –

+0

非常伤心@MarcAlff。这是我一小时以上的努力。信号可能会抛出错误,但根本不能解决根本问题。而我的解决方案需要从我的错误消息中删除前三个单词。它提供了100%的问题。顺便请使用信号解决方案..如果你是非常有信心downvote我的答案。这不是完美的解决方案,但它只有3个字。如果我在'字段列表'中以某种方式显示错误消息为“此类型的成员限制”,我认为这将是正确的答案。 (虽然提炼这个错误可能需要更多的工作) – Sami