2013-04-05 71 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