ALTER TABLE para adicionar uma chave primária composta

195

Eu tenho uma mesa chamada provider. Eu tenho três colunas chamadas person, place, thing. Pode haver pessoas duplicadas, lugares duplicados e coisas duplicadas, mas nunca pode haver uma combinação dupada de pessoa-lugar-coisa.

Como ALTER TABLE adicionaria uma chave primária composta para esta tabela no MySQL com essas três colunas?

David542
fonte

Respostas:

424
ALTER TABLE provider ADD PRIMARY KEY(person,place,thing);

Se uma chave primária já existe, você deseja fazer isso

ALTER TABLE provider DROP PRIMARY KEY, ADD PRIMARY KEY(person, place, thing);
Adrian Cornish
fonte
17
@ David542 Não, não - você pode ter apenas uma chave primária.
Adrian Cornish
35
@ David: é uma única chave primária composta de vários campos, também conhecida como chave composta.
Marc B
3
@ David542 Claro que você pode - esta é uma chave primária composta composta por 3 campos. A combinação dos 3 campos deve ser exclusiva.
Adrian Cornish
2
obrigado por postar - realmente me tirou de uma batalha com a interface do
usuário
1
um dos mais respostas preciosos em SO :)
alwbtc
21

A resposta de @Adrian Cornish está correta. No entanto, há outra ressalva em descartar uma chave primária existente. Se essa chave primária estiver sendo usada como chave estrangeira por outra tabela, você receberá um erro ao tentar descartá-la. Em algumas versões do mysql, a mensagem de erro estava incorreta (a partir de 5.5.17, essa mensagem de erro ainda é

alter table parent  drop column id;
ERROR 1025 (HY000): Error on rename of
'./test/#sql-a04_b' to './test/parent' (errno: 150).

Se você deseja soltar uma chave primária que está sendo referenciada por outra tabela, precisará soltar a chave estrangeira nessa outra tabela primeiro. Você pode recriar essa chave estrangeira se ainda desejar depois de recriar a chave primária.

Além disso, ao usar chaves compostas, a ordem é importante. Estes

1) ALTER TABLE provider ADD PRIMARY KEY(person,place,thing);
and
2) ALTER TABLE provider ADD PRIMARY KEY(person,thing,place);

não são a mesma coisa. Ambos reforçam a exclusividade nesse conjunto de três campos, no entanto, do ponto de vista da indexação, há uma diferença. Os campos são indexados da esquerda para a direita. Por exemplo, considere as seguintes consultas:

A) SELECT person, place, thing FROM provider WHERE person = 'foo' AND thing = 'bar';
B) SELECT person, place, thing FROM provider WHERE person = 'foo' AND place = 'baz';
C) SELECT person, place, thing FROM provider WHERE person = 'foo' AND place = 'baz' AND thing = 'bar';
D) SELECT person, place, thing FROM provider WHERE place = 'baz' AND thing = 'bar';

B pode usar o índice de chave primária na instrução ALTER 1
A pode usar o índice de chave primária na instrução ALTER 2
C pode usar o índice
D não pode usar o índice

A usa os dois primeiros campos no índice 2 como um índice parcial. A não pode usar o índice 1 porque não conhece a parte intermediária do índice. Ainda pode ser capaz de usar um índice parcial em apenas uma pessoa.

D não pode usar nenhum dos índices porque não conhece pessoas.

Veja os documentos do mysql aqui para mais informações.

cs_alumnus
fonte
@All - Você poderia compartilhar o equivalente em JPA pelo mesmo?
Pra_A
17

Você pode simplesmente querer uma restrição exclusiva. Especialmente se você já tiver uma chave substituta. (o exemplo de uma chave substituta já existente seria uma única coluna que é um AUTO_INCREMENT)

Abaixo está o código sql para uma restrição exclusiva

ALTER TABLE `MyDatabase`.`Provider`
    ADD CONSTRAINT CK_Per_Place_Thing_Unique UNIQUE (person,place,thing)
;
granadaCoder
fonte
Obrigado, uma restrição é o que eu queria, não sabia o que pedir neste post inicial. Obrigado por adicionar isso ao tópico.
ZaneDarken
Normalmente, uso uma chave substituta ...... e depois adiciono uma restrição exclusiva. Dessa forma .... se a "singularidade" mudar no caminho, não é muito dramático ajustar a restrição, em vez de mexer com a chave primária. E se você tiver tabelas derivadas às quais a chave estrangeira faça referência a essa tabela, será necessário apenas FK a chave substituta, não todas as 3 colunas. -
granadaCoder
3
alter table table_name add primary key (col_name1, col_name2);
Naveen Kumar Alonekar
fonte
1

Definitivamente, é melhor usar a COMPOSITE UNIQUE KEY, como o @GranadaCoder ofereceu, um exemplo um pouco complicado:

ALTER IGNORE TABLE table_name ADD UNIQUES INDEX idx_name(some_id, another_id, one_more_id);

Arthur Kushman
fonte
0

ALTER TABLE table_name DROP PRIMARY KEY,ADD PRIMARY KEY (col_name1, col_name2);

Por sorte
fonte