2013-04-05 29 views
0

在下面的表格:MYSQL触发另一列/约束的集合设定为等于列值的

Country Name    | Country Code | isStandardName 
---------------------------------------------------------- 

United States   | USA   | false 
---------------------------------------------------------- 
United States of America | USA   | True 
---------------------------------------------------------- 
Yankees     | USA   | false 

有那里有如美国/美国的美国与这些国家不同名的情况类似的国家代码(在这种情况下,美国),但其中一个可以是标准名称。在这种情况下,最简单的解决方案是强制执行约束,其中类似的国家代码一次只能在isStandardName部分中具有一个布尔值true。

换句话说,如何通过触发器/约束为一组相等的countryCode名称设置“CountryCode,'true'”是唯一的?

有关如何执行此约束的任何建议?

+0

如果我们尝试添加'独特(countryCode,isStandardName)'它也不会允许多于一个布尔'false'。所以根据要求,创建'trigger'会很好。 – Meherzad 2013-04-05 10:19:07

+0

也许,而不是'isStandardName',有一个'UNSIGNED INTEGER'组成的'priority'列。然后可以在'(countryCode,priority)'上定义'UNIQUE'约束,并将一些魔术值(例如0)作为“*标准名称*”。 – eggyal 2013-04-05 10:20:36

+0

但是独特的(countryCode,isStandardName)将不起作用,如果我们有三个USA和两个错误!甚至等于10的国家代码的数量可能会有所不同! – FidEliO 2013-04-05 10:22:43

回答

0

我做到了,同时保持表(因为它是)。

首先,检查规范国家一体化

DELIMITER // 
CREATE PROCEDURE `db`.`check_canonical_integrity` (IN new_countrycode 
    VARCHAR(10), IN new_iscanonical tinyint(1)) 
BEGIN 
SELECT sum(iscanonical) into @canonicalsum from `gapminder_db`.`COUNTRY_CODES` WHERE countrycode = new_countrycode; 
IF (@canonicalsum + new_iscanonical) > 1 THEN 
    SET @msg := 'More than one canonical countrycode cannot exit.'; 
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @msg; 
END IF; 
END 
//DELIMITER ; 

其次创建过程中,我们插入之前调用上面,你可以做同样的删除:

DELIMITER && 
CREATE TRIGGER `db`.`check_canonical_flag_insert` BEFORE INSERT ON 
`COUNTRY_CODES` 

FOR EACH ROW 
    BEGIN 
     CALL check_canonical_integrity(New.countrycode, New.iscanonical); 
    END&& 
DELIMITER ; 
1

我建议删除'isStandardName'列。创建一个表standard_country。创建了国家和standard_country之间的关系。使用左连接创建视图并更改模型以使用新结构。

例子。

CREATE TABLE `country` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `country` varchar(63) DEFAULT NULL, 
    `code` char(3) DEFAULT NULL COMMENT 'ISO 3166-1 alpha-3', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `country` (`country`,`code`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

INSERT INTO `country` (`id`, `country`, `code`) 
VALUES 
    (1,'United States','USA'), 
    (2,'United States of America','USA'), 
    (3,'Yankees','USA'); 

CREATE TABLE `standard_country` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `country_id` int(11) unsigned NOT NULL, 
    `code` char(3) NOT NULL DEFAULT '', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `key` (`code`), 
    KEY `country_id` (`country_id`), 
    CONSTRAINT `standard_country_ibfk_1` FOREIGN KEY (`country_id`) REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

INSERT INTO `standard_country` (`id`, `country_id`, `code`) 
VALUES 
    (1,2,'USA'); 

create or replace view countries_view as 
select country.id country_id 
, country 
, country.code 
, COALESCE((standard_country.id > 0) , 0) isStandard 
from `country` 
left join `standard_country` 
on country.id = standard_country.country_id 

-- example result 
select * from countries_view ; 

country_id country code isStandard 
1 United States USA 0 
2 United States of America USA 1 
3 Yankees USA 0 
+0

很好的解决方案。但我想避免在我的情况下创建新表,因为这个请求来自我们的DBA。 – FidEliO 2013-04-05 13:25:13

+0

如果我使用触发器,你有建议吗? – FidEliO 2013-04-05 14:58:05

+0

@FidEliO我看了一下触发器......凌乱......我建议把这个解决方案展示给你的DBA。如果您的DBA想要保留旧的结构,那么如果表中有一条记录可能会更改其值,那么如果同一表中的另一条记录已更改其值,则可以在数据访问层处理该值。 – 2013-04-07 03:51:38