Posso ter várias chaves primárias em uma única tabela?


Respostas:


559

Uma tabela pode ter uma chave primária composta, que é uma chave primária feita de duas ou mais colunas. Por exemplo:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

Atualização: Aqui está um link com uma descrição mais detalhada das chaves primárias compostas.


2
Neste exemplo, AMBOS ID do usuário e dados do usuário são necessários para identificar / localizar uma linha exclusiva. Não sabia qual era a intenção do OP, mas vim aqui para ver se conseguia identificar uma linha de maneira única com um de um conjunto de chaves. Por exemplo, eu gostaria de identificar um usuário único com um nome de usuário OU um ID do usuário, sem precisar de ambos. Eu acho que a resposta da RB a índices únicos faria o truque lá.
Burrito

11
@Benitok Como mencionado na resposta da RB. , Você pode usar Índices Exclusivos para fazer o que procura (uma coluna indexada exclusiva, independente de outras colunas indexadas exclusivas na mesma tabela). Certifique-se de consultar o seu sabor específico do manual do SQL para obter detalhes sobre a sintaxe exata do idioma usada.
04:00

195

Você pode ter apenas uma chave primária, mas pode ter várias colunas na sua chave primária.

Você também pode ter Índices exclusivos em sua tabela, que funcionará um pouco como uma chave primária, pois eles aplicarão valores exclusivos e agilizarão a consulta desses valores.


39

Uma tabela pode ter várias chaves candidatas. Cada chave candidata é uma coluna ou conjunto de colunas que são ÚNICAS, juntas e também NÃO NULAS. Portanto, especificar valores para todas as colunas de qualquer chave candidata é suficiente para determinar se há uma linha que atenda aos critérios ou nenhuma linha.

Chaves candidatas são um conceito fundamental no modelo de dados relacionais.

É prática comum, se várias chaves estiverem presentes em uma tabela, designar uma das chaves candidatas como chave primária. Também é prática comum fazer com que qualquer chave estrangeira da tabela faça referência à chave primária, em vez de qualquer outra chave candidata.

Eu recomendo essas práticas, mas não há nada no modelo relacional que exija a seleção de uma chave primária entre as chaves candidatas.


5
Acordado. Todas as chaves são iguais (nenhuma é 'primária') no modelo lógico. A escolha de qual chave na implementação física obtém a designação PRIMARY KEY é arbitrária e depende do fornecedor / produto.
onedaywhen 22/10/08

3
Eu diria que é dependente do designer de banco de dados.
precisa

Acabei de encontrar um caso de uso em que isso é necessário. Eu tenho uma tabela que será criada / gerenciada pelo Entity Framework - que, até onde eu sei, não suporta atualmente restrições compostas exclusivas de chave não primária. No entanto, ele suporta chaves primárias compostas. Os dados também serão vinculados a um sistema de banco de dados remoto que não suporta chaves compostas. Adotei a criação de uma PK composta no EF, mas também a adição de uma coluna GUID não anulável que o outro sistema pode usar para identificar exclusivamente.
Chris Nevill

2
Chris, eu disse que o modelo relacional não requer chaves primárias. Eu não disse nada sobre se alguma ferramenta poderia exigir isso. Mas eu entendo o seu ponto.
Walter Mitty

Eu acho que existe um requisito para que o PK seja mínimo, ou seja, use o menor número de colunas para identificar exclusivamente cada registro.
26618 gary

14

Esta é a resposta para a pergunta principal e para a pergunta de @ Kalmi sobre

Qual seria o sentido de ter várias colunas de geração automática?

Este código abaixo tem uma chave primária composta. Uma de suas colunas é incrementada automaticamente. Isso funcionará apenas no MyISAM. O InnoDB gerará um erro " ERRO 1075 (42000): definição de tabela incorreta; pode haver apenas uma coluna automática e deve ser definida como uma chave ".

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

2
Isso funciona se você especificar a coluna de incremento automático primeiro na definição de chave primária. (Talvez isso mudou, eu só testei em 5.6)
CTarczon

11

(Tenho estudado muito isso)

Chaves candidatas - é necessária uma combinação mínima de colunas para identificar exclusivamente uma linha da tabela.
Chaves compostas - 2 ou mais colunas.

  • Várias chaves Candidatas podem existir em uma tabela.
    • CHAVE Primária - Somente uma das chaves candidatas escolhidas por nós
    • Chaves alternativas - todas as outras chaves candidatas
      • As chaves primária e alternativa podem ser chaves compostas

Fontes:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key


6

Conforme observado pelos outros, é possível ter chaves primárias com várias colunas. Note-se, no entanto, que se você tiver algumas dependências funcionais que não são introduzidas por uma chave, considere normalizar sua relação.

Exemplo:

Person(id, name, email, street, zip_code, area)

Pode haver uma dependência funcional entre id -> name,email, street, zip_code and area Mas, frequentemente, a zip_codeé associado a areae, portanto, existe uma dependência funcional interna entre eles zip_code -> area.

Assim, pode-se considerar dividi-lo em outra tabela:

Person(id, name, email, street, zip_code)
Area(zip_code, name)

Para que seja consistente com a terceira forma normal .


6

Chave Primária é uma notação muito infeliz, devido à conotação de "Primária" e a associação subconsciente em conseqüência do Modelo Lógico. Assim, evito usá-lo. Em vez disso, refiro-me à Chave Substituta do Modelo Físico e às Chaves Naturais do Modelo Lógico.

É importante que o Modelo Lógico para cada Entidade tenha pelo menos um conjunto de "atributos de negócios" que compreendam uma Chave para a entidade. Boyce, Codd, Date e outros se referem a eles no Modelo Relacional como Chaves Candidatas. Quando criamos tabelas para essas Entidades, as Chaves Candidatas se tornam Chaves Naturais nessas tabelas. É somente através dessas Chaves Naturais que os usuários conseguem identificar exclusivamente as linhas nas tabelas; como chaves substitutas sempre devem estar ocultas dos usuários. Isso ocorre porque as Chaves Substitutas não têm significado comercial.

No entanto, o Modelo Físico para nossas tabelas, em muitos casos, será ineficiente sem uma Chave de Substituição. Lembre-se de que as colunas não cobertas de um índice não agrupado em cluster só podem ser encontradas (em geral) por meio de uma Pesquisa de Chave no índice agrupado (ignore as tabelas implementadas como pilhas por um momento). Quando nossas Chaves Naturais disponíveis são amplas, isso (1) aumenta a largura de nossos nós de folhas não agrupados em cluster, aumentando os requisitos de armazenamento e os acessos de leitura para pesquisas e varreduras desse índice não agrupado; e (2) reduz a dispersão do índice em cluster, aumentando a altura e o tamanho do índice, aumentando novamente os requisitos de leitura e armazenamento para os índices em cluster; e (3) aumenta os requisitos de cache para nossos índices em cluster. perseguindo outros índices e dados fora do cache.

É aqui que uma pequena chave substituta, designada ao RDBMS como "a chave primária", é benéfica. Quando definida como a chave de cluster, para ser usada para pesquisas de chaves no índice de cluster de índices não em cluster e pesquisas de chave estrangeira de tabelas relacionadas, todas essas desvantagens desaparecem. Nossas fan-outs de índice em cluster aumentam novamente para reduzir a altura e o tamanho do índice em cluster, reduz a carga de cache para nossos índices em cluster, diminuem as leituras ao acessar dados através de qualquer mecanismo (seja varredura de índice, busca de índice, pesquisa de chave sem cluster ou pesquisa de chave estrangeira) e diminuir os requisitos de armazenamento para índices em cluster e não clusterizado de nossas tabelas.

Observe que esses benefícios ocorrem apenas quando a chave substituta é pequena e a chave de cluster. Se um GUID for usado como chave de cluster, a situação geralmente será pior do que se a menor chave natural disponível tivesse sido usada. Se a tabela estiver organizada como um heap, o RowID de 8 bytes (heap) será usado para pesquisas de chaves, o que é melhor que um GUID de 16 bytes, mas com menos desempenho que um número inteiro de 4 bytes.

Se um GUID precisar ser usado devido a restrições de negócios, vale a pena procurar uma chave de cluster melhor. Se, por exemplo, um identificador de site pequeno e um "número de sequência de site" de 4 bytes for possível, esse design poderá oferecer um desempenho melhor que um GUID como Chave Substituta.

Se as consequências de um heap (junção de hash talvez) tornarem o armazenamento preferido, os custos de uma chave de cluster mais ampla precisam ser equilibrados na análise de trade-off.

Considere este exemplo ::

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

onde a tupla " (P_Id, LastName) " requer uma restrição de exclusividade e pode ser um Sobrenome Unicode longo mais um número inteiro de 4 bytes, seria desejável (1) impor declarativamente essa restrição como " ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id , Sobrenome) "e (2) declaram separadamente uma Chave Substituta pequena como a" Chave Primária "de um índice em cluster. Vale a pena notar que o Anita possivelmente deseja apenas adicionar o Sobrenome a essa restrição para tornar esse campo coberto, o que é desnecessário em um índice clusterizado porque TODOS os campos são cobertos por ele.

A capacidade do SQL Server de designar uma Chave Primária como não clusterizada é uma circunstância histórica infeliz, devido a uma combinação do significado "chave natural ou candidata preferida" (do Modelo Lógico) com o significado "chave de pesquisa no armazenamento" do Physical Modelo. Meu entendimento é que o SYBASE SQL Server originalmente sempre usava um RowID de 4 bytes, em um heap ou em um índice clusterizado, como a "chave de pesquisa no armazenamento" do Modelo Físico.


3
Você pode traduzir isso para o inglês!
Jasir

3

Algumas pessoas usam o termo "chave primária" para significar exatamente uma coluna inteira que obtém seus valores gerados por algum mecanismo automático. Por exemplo, AUTO_INCREMENTno MySQL ou IDENTITYno Microsoft SQL Server. Você está usando a chave primária nesse sentido?

Nesse caso, a resposta depende da marca do banco de dados que você está usando. No MySQL, você não pode fazer isso, você recebe um erro:

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

Em algumas outras marcas de banco de dados, você pode definir mais de uma coluna de geração automática em uma tabela.


5
Qual seria o sentido de ter várias colunas de geração automática?
Tarnay Kálmán

Não tenho um caso de uso em mente, mas, se houver alguma necessidade, algumas marcas de banco de dados suportariam isso e outras não. É tudo o que estou dizendo.
22477 Bill Karwin

11
Aqui está um caso: em uma tabela de pedidos, eu tenho um ID (incrementado automaticamente) e um ID externo (seqüências de caracteres semelhantes a hash); ambos devem ser únicos; portanto, teoricamente, você pode dizer que ambos são "primários". é claro que isso pode ser feito com um índice exclusivo secundário, mas ainda é um caso legítimo (IMHO)
Nir

2

Ter duas chaves primárias ao mesmo tempo, não é possível. Mas (supondo que você não tenha estragado o caso com chave composta), pode ser o que você precisa é tornar um atributo único.

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

No entanto, observe que no banco de dados relacional uma 'super chave' é um subconjunto de atributos que identificam exclusivamente uma tupla ou linha em uma tabela. Uma 'chave' é uma 'super chave' que possui uma propriedade adicional que remove qualquer atributo da chave, faz com que essa chave não seja mais uma 'super chave' (ou simplesmente uma 'chave' é uma super chave mínima). Se houver mais chaves, todas elas são chaves candidatas. Selecionamos uma das chaves candidatas como chave primária. É por isso que falar sobre várias chaves primárias para uma relação ou tabela está sendo um conflito.


A Wikipedia não tem uma definição para 'chave'. Além disso, "remover qualquer atributo da chave torna essa chave uma 'super chave'" não significou nada para mim, pois ao remover um atributo da super chave ainda pode ser uma super chave.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Sim, nesse caso, seu conjunto de atributos não é uma 'chave', mas uma 'super chave'. O que quero dizer é que, se um conjunto de atributos para ser uma 'chave', o conjunto deve ser mínimo ou o conjunto deve ter uma propriedade adicional que, removendo qualquer atributo do conjunto, faça com que o conjunto resultante não seja mais uma 'super chave'.
Rusiru Adithya Samarasinghe 10/04

Parece que o seu significado real de 'chave' é Candidate_key ( en.wikipedia.org/wiki/Candidate_key ), pode ser que deva ser mencionado.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Sim, eu já mencionei isso na minha resposta. "Se houver mais chaves, todas elas são chaves candidatas". De qualquer forma, obrigado pela sua análise.
Rusiru Adithya Samarasinghe 12/04/19

1. Quando você menciona "Se houver mais chaves, todas elas são chaves candidatas", ... Você quer dizer o contrário / senão, elas não são chaves candidatas? ... 2. Onde está a outra parte? ... Somos a mesma página?
Manohar Reddy Poreddy

1

Uma chave primária é a chave que identifica exclusivamente um registro e é usada em todos os índices. É por isso que você não pode ter mais de um. Geralmente, também é a chave usada para ingressar em tabelas filho, mas isso não é um requisito. O objetivo real de uma PK é garantir que algo permita identificar exclusivamente um registro, para que as alterações nos dados afetem o registro correto e para que os índices possam ser criados.

No entanto, você pode colocar vários campos em uma chave primária (uma PK composta). Isso tornará suas junções mais lentas (especialmente se forem campos maiores do tipo string) e seus índices maiores, mas poderá remover a necessidade de fazer junções em algumas das tabelas filho, portanto, quanto ao desempenho e design, leve-os em um caso caso a caso. Quando você faz isso, cada campo em si não é exclusivo, mas a combinação deles é. Se um ou mais dos campos em uma chave composta também forem exclusivos, você precisará de um índice exclusivo. É provável que, se um campo for único, este seja um candidato melhor para o PK.

Agora, às vezes, você tem mais de um candidato para o PK. Nesse caso, você escolhe um como PK ou usa uma chave substituta (eu pessoalmente prefiro chaves substitutas para esta instância). E (isso é crítico!), Você adiciona índices exclusivos a cada uma das chaves candidatas que não foram escolhidas como PK. Se os dados precisam ser exclusivos, eles precisam de um índice exclusivo, seja o PK ou não. Este é um problema de integridade de dados. (Observe que isso também é verdade sempre que você usa uma chave substituta; as pessoas enfrentam problemas com chaves substitutas porque esquecem de criar índices exclusivos nas chaves candidatas.)

Ocasionalmente, há momentos em que você deseja mais de uma chave substituta (que geralmente é a PK, se você a possuir). Nesse caso, o que você deseja não é mais PK, são mais campos com chaves geradas automaticamente. A maioria dos bancos de dados não permite isso, mas existem maneiras de contornar isso. Primeiro, considere se o segundo campo pode ser calculado com base na primeira chave gerada automaticamente (campo1 * -1 por exemplo) ou talvez a necessidade de uma segunda chave gerada automaticamente realmente signifique que você deve criar uma tabela relacionada. As tabelas relacionadas podem estar em um relacionamento um para um. Você aplicaria isso adicionando a PK da tabela pai à tabela filha e, em seguida, adicionando o novo campo gerado automaticamente à tabela e, em seguida, quaisquer campos apropriados para esta tabela. Em seguida, escolha uma das duas chaves como PK e coloque um índice exclusivo na outra (o campo gerado automaticamente não precisa ser uma PK). E certifique-se de adicionar o FK ao campo que está na tabela pai. Em geral, se você não tiver campos adicionais para a tabela filho, precisará examinar por que acha que precisa de dois campos gerados automaticamente.


0

Boas respostas técnicas foram dadas da melhor maneira possível. Eu sou apenas pode adicionar a este tópico:

Se você deseja algo que não é permitido / aceitável, é uma boa razão para dar um passo atrás.

  1. Entenda o núcleo do motivo pelo qual não é aceitável.
  2. Pesquise mais na documentação / artigos de periódicos / web e etc.
  3. Analise / revise o projeto atual e aponte grandes falhas.
  4. Considere e teste todas as etapas durante o novo design.
  5. Sempre espere e tente criar uma solução adaptável.

Espero que ajude alguém.


11
conselhos genéricos (embora úteis), não uma resposta para uma pergunta específica.
Bradford Needham #

-3

Sim, é possível no SQL, mas não podemos definir mais de uma chave primária no MsAccess. Então, não conheço os outros bancos de dados.

CREATE TABLE CHAPTER (
    BOOK_ISBN VARCHAR(50) NOT NULL,
    IDX INT NOT NULL,
    TITLE VARCHAR(100) NOT NULL,
    NUM_OF_PAGES INT,
    PRIMARY KEY (BOOK_ISBN, IDX)
);

Uma tabela SQL pode ter apenas um PK.
philipxy 14/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.