【问题标题】:MYSQL Trigger/Constraint for set of equal column value in another column另一列中一组相等列值的MYSQL触发器/约束
【发布时间】:2013-04-05 10:12:07
【问题描述】:

如下表:

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

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

有一种情况,例如美国/美国等国家有不同的名称,国家代码相似(在本例中为美国),但其中一个可以是标准名称。在这种情况下,最简单的解决方案是强制执行一个约束,在该约束中,类似的国家/地区代码一次只能在 isStandardName 部分中包含一个布尔值 true。

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

关于如何强制执行此约束的任何建议?

【问题讨论】:

  • 如果我们尝试添加unique(countryCode, isStandardName),它也不允许超过1个布尔值false。因此,根据要求,最好创建trigger
  • 也许,而不是 isStandardName,有一个由 UNSIGNED INTEGER 组成的 priority 列。然后可以在(countryCode, priority) 上定义UNIQUE 约束,并将一些神奇的值(例如0)视为“标准名称”。
  • 但是如果我们有三个 USA 和两个 false,则 unique (countryCode, isStandardName) 将不起作用!相等的 countryCode 的数量甚至可以变化到 10 个!
  • 我认为再添加一列只会使情况更加复杂。我试图避免添加更多列。
  • @FidEliO:这就是我说“而不是...”的原因。

标签: mysql sql triggers constraints


【解决方案1】:

我建议删除“isStandardName”列。创建一个表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

【讨论】:

  • 不错的解决方案。但我正在考虑避免在我的情况下创建新表,因为这个请求来自我们的 DBA。
  • 如果我使用触发器,你有什么建议吗?
  • @FidEliO 我看了一下触发器......很乱......我建议向您的 DBA 展示这个解决方案。如果同一表中的另一条记录更改了其值,则表中的一条记录可能会更改其值,如果您的 DBA 想要保留旧结构,则可以在数据访问层中处理。
  • 我同意你的看法。但他有一个想法,即 DAL 不应该被编码来处理这些东西。不过谢谢你的回答。
【解决方案2】:

我这样做的同时将桌子保持为一体(原样)。

首先,创建检查规范国家整合的程序

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 ;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    相关资源
    最近更新 更多