来自两列的MYSQL唯一(交叉唯一)

时间:2020-09-12 07:50:03

标签: mysql unique

我有一个包含两列'NAME''ALIAS'的表格。 我希望这两列的内容都是唯一的。 因此,我无法创建已经在'ALIAS'中的'NAME',反之亦然。

enter image description here

不允许使用“ NAME” B,因为先前已在列中使用B 'ALIAS';

不允许使用“ ALIAS” A,因为以前在列中使用了A “ NAME”;

允许使用

“ NAME” C,因为以前从未使用过“ C” 允许使用“名称”列,“别名”列和“别名” D,因为 从未在“名称”列和“ “ ALIAS”列;

...

我希望“ NAME”列和“ ALIAS”列中的数据唯一 列

我已经尝试过这种方式,

CREATE TABLE `Group` (
  Name VARCHAR(50) NOT NULL DEFAULT '',
  Alias VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (Name)
)
ENGINE = MYISAM,
CHECKSUM = 0;

ALTER TABLE `Group` ADD CONSTRAINT Constraint_Group UNIQUE KEY(`Name`, `Alias`);

但“唯一”仅适用于相应的列。

有没有办法得到它?

谢谢。

2 个答案:

答案 0 :(得分:0)

您可以从一个表中提取可能的名称,该表在UNIQUE列上有一个name约束。这样,您就不能将名称用于多个目的。为了使这项工作切实可行,您将需要另外一列指定名称的类型(如果是用于组名或别名)。您将此列用作外键的一部分。

注意:要运行此功能,您将需要(并且应该始终使用)InnoDB storage engine,以便可以使用外键。

首先,为“所有”可能的名称创建一个表。

CREATE TABLE names (
    id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
    name VARCHAR(300) NOT NULL,
    kind VARCHAR(15) NOT NULL,
    CONSTRAINT UQ_name UNIQUE(name), 
    CONSTRAINT CH_names_kind CHECK (kind IN ('name', 'alias')),
    KEY IX_names_nameAndKind (name, kind)
);

(您需要使用MySQL 8来使CHECK语句正常工作)

如您所见,name列具有UNIQUE约束,因此您不能有重复的条目。同样,每个条目都必须是'name''alias'的{​​{1}}条目中的一种,并且由于名称不能重复,因此必须选择。您可以按照以下步骤填写条目:

CHECK

现在最棘手的部分是组表。您不仅需要引用列INSERT INTO names (name, kind) VALUES ('A', 'name'); INSERT INTO names (name, kind) VALUES ('B', 'alias'); INSERT INTO names (name, kind) VALUES ('C', 'name'); ,还必须组合引用name。这也是kind表中有键IX_names_nameAndKind的原因。因此,您可以引用多列索引namesname,而不是从其他表中引用自动增量列的id值。您可以为组的名称以及组的可选别名执行此操作。 kind语句可能看起来像这样:

CREATE TABLE

外键CREATE TABLE grps ( id INT AUTO_INCREMENT PRIMARY KEY NOT NULL, name VARCHAR(300) NOT NULL, nameKind VARCHAR(15) NOT NULL, alias VARCHAR(300) NULL, aliasKind VARCHAR(15) NULL, FOREIGN KEY FK_grps_nameAndNameKind (name, nameKind) REFERENCES names (name, kind), CONSTRAINT CH_grps_nameKind CHECK (nameKind IN ('name')), FOREIGN KEY FK_grps_aliasAndAliasKind (alias, aliasKind) REFERENCES names (name, kind), CONSTRAINT CH_grps_aliasKind CHECK (aliasKind IN ('alias')) ); 指出,列FK_grps_nameAndNameKindname必须来自nameKind表(列names和{{1 }}。 namekind列的外键FK_grps_aliasAndAliasKind也是如此。但是这里的窍门是限制alias列只允许值aliasKind,而nameKind列只允许值'name'(请参阅aliasKind声明)。因此,在引用组名时,它的类型必须为'alias';在引用别名时,它的名称必须是类型CHECK。您可以按如下所示填写表格:

'name'

当您尝试破坏支票和外键时,您会收到预期的错误消息:

'alias'
INSERT INTO grps (name, nameKind, alias, aliasKind) VALUES ('A', 'name', NULL, NULL);
INSERT INTO grps (name, nameKind, alias, aliasKind) VALUES ('C', 'name', 'B', 'alias');

答案 1 :(得分:0)

@Michael - sqlbotthis thread中得到答案

使用Triger满足我的需求。

DROP TABLE IF EXISTS Groups;

CREATE TABLE groups (
  Name varchar(50) NOT NULL DEFAULT '',
  Alias varchar(50) DEFAULT NULL,
  PRIMARY KEY (Name)
)
ENGINE = MYISAM,
CHARACTER SET utf8,
CHECKSUM = 0,
COLLATE utf8_general_ci;

ALTER TABLE groups
ADD UNIQUE INDEX Alias (Alias);


CREATE TRIGGER trg_Ins BEFORE INSERT ON groups FOR EACH ROW
  BEGIN
      DECLARE err_msg VARCHAR(128) DEFAULT NULL; 
      
      IF EXISTS(SELECT x.alias FROM groups x WHERE x.alias = NEW.name) OR (NEW.Name=New.Alias) THEN
          SET err_msg = CONCAT_WS('','cannot insert Name value ',NEW.Name,'; already exists as a Alias');
          SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
      END IF;

      IF EXISTS(SELECT x.Name FROM groups x WHERE x.Name = NEW.Alias) OR (NEW.Alias=NEW.Name)  THEN
          SET err_msg = CONCAT_WS('','cannot insert Alias value ',NEW.Alias,'; already exists as a Name');
          SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
      END IF;
  END;

CREATE TRIGGER trg_Upd BEFORE UPDATE ON groups FOR EACH ROW
  BEGIN
      DECLARE err_msg VARCHAR(128) DEFAULT NULL; 
      
      IF EXISTS(SELECT x.alias FROM groups x WHERE x.alias = NEW.name) OR (NEW.Name=New.Alias) THEN
          SET err_msg = CONCAT_WS('','cannot Update Name value ',NEW.Name,'; already exists as a Alias');
          SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
      END IF;

      IF EXISTS(SELECT x.Name FROM groups x WHERE x.Name = NEW.Alias) OR (NEW.Alias=NEW.Name)  THEN
          SET err_msg = CONCAT_WS('','cannot Update Alias value ',NEW.Alias,'; already exists as a Name');
          SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
      END IF;
  END;

-- TEST INSERT

Insert INTO Groups VALUES ('A','B');  -- OK

Insert INTO Groups VALUES ('B',NULL); -- cannot insert Name value B; already exists as a Alias 

Insert INTO Groups VALUES ('C','A'); --  cannot insert Alias value A; already exists as a Name

Insert INTO Groups VALUES ('C','D'); -- OK

Insert INTO Groups VALUES ('E','Z'); -- OK

Insert INTO Groups VALUES ('K','K'); -- cannot insert Name value K; already exists as a Alias

-- TEST UPDATE
UPDATE groups SET `Name`='A' WHERE `Name`='C'; -- Duplicate entry 'A' for key

UPDATE groups set `Name` ='X' WHERE `Name`='E'; -- OK

UPDATE groups set `Alias` ='A' WHERE `Name`='X'; -- cannot Update Name value B; already exists as a Alias

-将尝试更多测试