4

所以在我解释我的问题之前,这里有几个精简的表定义来帮助说明我的问题:

-- 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。如果尝试将新记录插入到 Type_ID = 4 的 Member_Infos 表中,并且在 Member_Infos 表中 Type_ID <= 5 的记录计数比数据被插入,否则被拒绝。任何建议将不胜感激。

4

4 回答 4

3

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

INSERT INTO member_infos
SELECT      1, 'Timothy', 'secret', 'me@myself.com', 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 的情况。如果不满足计数条件,这将忽略,并且仅当 member_info 中类型 id = 5 的条目的成员计数小于member_types表中设置的限制时才插入

于 2012-11-09T07:13:24.403 回答
1

在 MySQL 中,触发器可能是在数据库级别执行此操作的正确方法。

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

于 2012-11-09T10:17:08.907 回答
1

要引发错误,请在触发器中使用 SIGNAL 语句。

http://dev.mysql.com/doc/refman/5.5/en/signal.html

于 2012-11-09T10:07:01.013 回答
0

Sql Fiddle 演示链接

您可以尝试通过添加以下插入语句

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

在整个代码的末尾。不允许您进行此插入,因为type_id=2允许 0 条记录member_ifostype_id=5同样,插入五个记录后,您将在插入时出错。

我添加了一个触发器,因为您需要对每个新条目进行验证,而不是一些静态值。所以它不是同一个问题,dual 可以像 MySQL Conditional Insert这样的 SO 上的一些问题一样工作,因为你需要 new.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'。需要此异常,因为它会阻止在询问者所需条件下插入。但改进将不胜感激。我无法解决它。

于 2012-11-09T10:57:19.903 回答