Comment spécifier une contrainte unique pour plusieurs colonnes dans MySQL?

865

J'ai une table:

table votes (
    id,
    user,
    email,
    address,
    primary key(id),
);

Maintenant, je veux rendre les colonnes utilisateur, email, adresse uniques (ensemble).

Comment faire cela dans MySql?

Bien sûr, l'exemple est juste ... un exemple. Alors, ne vous inquiétez pas de la sémantique.

Niyaz
la source

Réponses:

1436
ALTER TABLE `votes` ADD UNIQUE `unique_index`(`user`, `email`, `address`);
jonstjohn
la source
31
Cela fonctionnerait-il correctement avec la clause ON DUPLICATE KEY des instructions INSERT? Autrement dit, si j'essayais d'insérer une ligne en conflit avec les valeurs d'utilisateur / de messagerie / d'adresse d'une autre ligne, INSERT ferait-il les actions spécifiées par la clause ON DUPLICATE KEY à la place?
clizzin
6
De cette façon, une combinaison de trois serait unique? Ou les trois colonnes individuelles seraient-elles uniques?
Gary Lindahl
95
Pour les personnes utilisant MySQL Workbench: allez dans l'onglet Index et sélectionnez UNIQUE comme type. Donnez un nom à votre index et vérifiez les colonnes appropriées dans la section "Colonnes d'index"
Pakman
10
Comme moi, si quelqu'un d'autre a trouvé cela dans les moteurs de recherche ... et pour répondre à la question de Clizzin sur si ON DUPLICATE KEY fonctionnera avec une clé composite - cela le fera absolument, mais cela nécessitera quelques ajustements mineurs à la syntaxe. voir stackoverflow.com/questions/9537710/…
Joe
2
comment le faire fonctionner même avec une valeur NULL. Si nous insérons deux mêmes lignes avec une valeur NULL, cela ne fonctionne pas ...
Wasim A.
237

J'ai une table MySQL:

CREATE TABLE `content_html` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_box_elements` int(11) DEFAULT NULL,
  `id_router` int(11) DEFAULT NULL,
  `content` mediumtext COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_box_elements` (`id_box_elements`,`id_router`)
);

et la CLÉ UNIQUE fonctionne comme prévu, elle autorise plusieurs lignes NULL d'id_box_elements et id_router.

J'utilise MySQL 5.1.42, donc il y a probablement eu une mise à jour sur le problème discuté ci-dessus. Heureusement, cela fonctionne et j'espère que cela restera ainsi.

Frodik
la source
34
Je voulais marquer cette réponse car elle vous montre comment créer une nouvelle table avec un index unique alors que la réponse de jonstjohn ci-dessus vous indique comment mettre à jour une table existante. Ils font la même chose, mais cela dépend simplement de la création d'une nouvelle table ou de la mise à jour d'une table existante. :)
GazB
3
qu'est-ce qui se passe avec toutes les citations, servent-elles à quelque chose?
puk
8
C'est une sortie d'Adminer (www.adminer.org) qui insère ces backquotes automatiquement, donc il n'y a aucun problème avec la collision des mots-clés mysql utilisés comme noms de colonne.
Frodik
50

Les index uniques multi-colonnes ne fonctionnent pas dans MySQL si vous avez une valeur NULL en ligne car MySQL traite NULL comme une valeur unique et n'a actuellement pas de logique pour le contourner dans les index multi-colonnes. Oui, le comportement est insensé, car il limite beaucoup d'applications légitimes d'index multi-colonnes, mais c'est ce qu'il est ... Pour l'instant, c'est un bug qui a été estampillé "ne sera pas corrigé" sur le MySQL bug-track ...

niksoft
la source
11
Deux points de clarification: 1) ce comportement ne tient pas ENGINE BDBet, 2) il s'agit d' un comportement documenté , bien que, à mon humble avis, pas suffisamment documenté étant donné à quel point il peut être surprenant / désagréable. Voir le bogue MySQL 25544 bugs.mysql.com/bug.php?id=25544 pour une discussion.
pilcrow
2
Merci pour le NULL heads up, résolu le problème que je rencontrais ... Je pense que je vais y aller avec une somme de contrôle de hachage
Daniel Doezema
7
Ce n'est pas une réponse. Ce devrait être un commentaire à la question d'origine.
Expiation limitée du
Les documents officiels disent: Notez que depuis MySQL 5.1, BDB n'est plus pris en charge.
George
2
Très bonne information, mais pas de réponse. N'est que marginalement lié à la question.
billynoah
23

Avez-vous essayé cela?

UNIQUE KEY `thekey` (`user`,`email`,`address`)
Erick
la source
Ce que Erick dit fonctionne très bien pour moi: UNIQUE KEY thekey` ( user, email, address) `. J'utilise la version 5.5.24 de MYSQL Vous pouvez définir cela même dans PHPMYADMIN si vous l'utilisez. J'utilise la version 3.5.1 de PMA.
WQC
Je l'ai essayé avec MySql 5.6. Fonctionne dès le premier essai. Merci Erick!
Lawrence
11

Cela fonctionne pour la version 5.5.32 de mysql

ALTER TABLE  `tablename` ADD UNIQUE (`column1` ,`column2`);
rizon
la source
1
Il semble fonctionner sans les guillemets simples sur le nom de la colonne.
Pratik Singhal
7

MySql 5 ou supérieur se comporte comme ceci (je viens de tester):

  • vous pouvez définir des contraintes uniques impliquant des colonnes nullables. Disons que vous définissez une contrainte unique (A, B) où A n'est pas annulable mais B est
  • lors de l'évaluation d'une telle contrainte, vous pouvez avoir (A, null) autant de fois que vous le souhaitez (même valeur A!)
  • vous ne pouvez avoir qu'une seule paire (A, pas null B)

Exemple: PRODUCT_NAME, PRODUCT_VERSION 'glass', null 'glass', null 'wine', 1

Maintenant, si vous essayez d'insérer à nouveau ('wine' 1), il signalera une violation de contrainte J'espère que cela vous aidera

Cristian Botiza
la source
merci d'avoir expliqué. J'ai unique (A, B, C) et je ne savais pas pourquoi cela permettait des combinaisons de null avec les mêmes options non nulles
Alexandru Topală
6

Vous pouvez ajouter des index uniques à plusieurs colonnes via phpMyAdmin . (J'ai testé dans la version 4.0.4)

Accédez à la page de structure de votre table cible. Ajoutez un index unique à l'une des colonnes. Développez la liste des index en bas de la page de structure pour voir l'index unique que vous venez d'ajouter. Cliquez sur l'icône de modification et, dans la boîte de dialogue suivante, vous pouvez ajouter des colonnes supplémentaires à cet index unique.

Vince K
la source
3

Je le fais comme ça:

CREATE UNIQUE INDEX index_name ON TableName (Column1, Column2, Column3);

Ma convention pour un unique index_nameest TableName_Column1_Column2_Column3_uindex.

Sam Malayek
la source
2

Pour ajouter un index unique, les éléments suivants sont requis:

1) nom_table
2) nom_index
3) colonnes sur lesquelles vous souhaitez ajouter un index

ALTER TABLE  `tablename` 
ADD UNIQUE index-name
(`column1` ,`column2`,`column3`,...,`columnN`);

Dans votre cas, nous pouvons créer un index unique comme suit:

ALTER TABLE `votes`ADD 
UNIQUE <votesuniqueindex>;(`user` ,`email`,`address`);
sandeep vanama
la source
1

Si vous souhaitez éviter les doublons à l'avenir. Créez une autre colonne, par exemple id2.

UPDATE tablename SET id2 = id;

Ajoutez maintenant l'unique sur deux colonnes:

alter table tablename add unique index(columnname, id2);
kumar
la source
1

Si vous créez une table dans mysql, utilisez alors:

create table package_template_mapping (
mapping_id  int(10) not null auto_increment  ,
template_id int(10) NOT NULL ,
package_id  int(10) NOT NULL ,
remark      varchar(100),
primary key (mapping_id) ,
UNIQUE KEY template_fun_id (template_id , package_id)
);
Devendra Singraul
la source
0

Débarrassez-vous d'abord des doublons existants

delete a from votes as a, votes as b where a.id < b.id 
and a.user <=> b.user and a.email <=> b.email 
and a.address <=> b.address;

Ajoutez ensuite la contrainte unique

ALTER TABLE votes ADD UNIQUE unique_index(user, email, address);

Vérifiez la contrainte avec

SHOW CREATE TABLE votes;

Notez que l'utilisateur, l'adresse e-mail et l'adresse seront considérés comme uniques si l'un d'eux a une valeur nulle.

Ganesh Krishnan
la source
0

Pour PostgreSQL ... Cela n'a pas fonctionné pour moi avec index; cela m'a donné une erreur, alors j'ai fait ceci:

alter table table_name
add unique(column_name_1,column_name_2);

PostgreSQL a donné à l'index unique son propre nom. Je suppose que vous pouvez changer le nom de l'index dans les options de la table, si cela doit être changé ...

bugthefifth
la source