O uso de várias restrições exclusivas em uma única tabela é considerado um design ruim?

8

Eu estava olhando a INSERT INTO .. ON CONFLICT (..) DO UPDATE ..sintaxe do PostgreSQL e percebi que você não pode fazer várias verificações de restrição exclusivas com ele. Quero dizer, você se refere a um índice exclusivo composto pelos nomes das colunas ON CONFLICT (Name, Symbol)(se o índice exclusivo estiver definido para essas duas colunas) ou usa a chave primária. Se você definir dois índices exclusivos separados para as colunas, poderá verificar apenas um.

CREATE TABLE student
    (Id int primary key, Name varchar(50), Symbol varchar(50),
      CONSTRAINT col1_unique UNIQUE (Name),
      CONSTRAINT col2_unique UNIQUE (Symbol)
    ); 

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (1, 'John', 'J'),
    (2, 'David', 'D'),
    (3, 'Will', 'W');

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (4, 'Jeremy', 'J')
   on conflict(Name) DO UPDATE
   set Name = 'Jeremy';

Pode gerar um erro, dizendo que Jé uma duplicata. No entanto, este exemplo é simplesmente um design ruim, porque o símbolo deve estar em outra tabela e ser conectado à tabela do aluno por meio de um relacionamento um para muitos. É por isso que me pergunto, talvez o PostgreSQL tenha on conflictsido projetado dessa maneira, porque você SEMPRE pode reestruturar as tabelas de uma maneira, onde existe apenas um único índice. É verdade ou existe outra razão?

Exemplo de violino: http://www.sqlfiddle.com/#!17/9c0ce

appl3r
fonte
você SEMPRE pode reestruturar as tabelas de uma maneira, onde existe apenas um único índice. Existem EntityA e EntityB. Existem 2 instâncias de cada. Qualquer instância EntityA pode ser combinada com qualquer instância EntityB, portanto, existem 2 combinações possíveis em que todas as instâncias são usadas. Uma dessas combinações é realizada e você deve armazená-la. Agora tente criar um esquema em que não exista tabela com 2 únicos com todas as restrições que impeçam dados ilegais.
Akina
@Akina, perdi o seu ponto. Se duas entidades estiverem conectadas por meio de um relacionamento muitos para muitos, você criará uma tabela de links, armazenando suas chaves estrangeiras, para que não haja tabela com 2 índices exclusivos.
Apl3r #
Uma instância pode ser usada apenas uma vez, portanto, você deve ter 2 índices uniqie em uma tabela vinculada (por cada entidade separadamente) para impedir o uso da instância já usada.
Akina
Embora isso seja verdade, isso é um incômodo: veja a amostra na resposta de Michael Green. Dividir uma tabela tão simples em 4 tabelas é definitivamente uma dor de cabeça, já que é uma descrição simples, não é como se você precisasse da opção "ON CONFLICT".
Walfrat

Respostas:

8

Sempre existe o sexto, ou chave de domínio, forma normal. Aqui cada coluna não chave se torna sua própria tabela. Portanto, a tabela 3NF T (Chave, Col1, Col2, ..) torna-se T1 (Chave, Col1), T2 (Chave, Col2) etc. Essas novas tabelas que requerem exclusividade podem ser declaradas.

Porém, acho que ter várias restrições únicas em uma tabela é perfeitamente aceitável. Tomemos, por exemplo, uma tabela de países. Isso teria, digamos, um ID, o nome, o código ISO, a capital e alguns outros. Cada um desses quatro primeiros será único. Além disso, se queremos que nosso sistema confie em cada um como único, acredito que devemos definir restrições únicas para cada um. Isso reforça verdades sobre os dados nos quais todos os consumidores podem confiar.

Michael Green
fonte
Você acha que o design do postgresql é apenas o resultado da miopia? Oracle, SQL Server, DB2 e outros oferecem uma maneira de levar em consideração todas as chaves exclusivas nessa situação (usando a MERGEinstrução). A página ON CONFLICT DO UPDATE foi adicionada apenas na versão 9.5 e é muito mais limitada.
Appl3r #
11
@ appl3r é apenas um detalhe de implementação. Você pode fazer isso ON CONFLICT DO NOTHINGsem mencionar restrições exclusivas e ele considerará todas elas (e não fará nada). Quando você quer fazer ON CONFLICT DO UPDATE, você deve declarar uma coluna ou restrição e apenas uma. A restrição pode ser levantada em versões futuras.
precisa saber é o seguinte
Estou um pouco confuso com o seu primeiro parágrafo. Digamos que dividimos a tabela Student (ID, Nome, Símbolo) do OP em S1 (Id, Nome) e S2 (Id, Símbolo) para tentar transformá-la em DK / NF. Quais seriam as principais restrições (domínio e) no S2 e como eles garantiriam que cada aluno tivesse um único ID único e um único símbolo único?
Ilmari Karonen 03/10/19
11
A questão era (tipo de) "Se vários índices UNIQUE são muito bem, por isso que o PostgreSQL requer que um índice árbitro é especificado para ON CONFLICT ... DO UPDATEe, infelizmente, esta resposta não aborda esse ponto.
AndreKR
O @AndreKR aborda o (em negrito): "foi (esse recurso do Postgres) projetado desta maneira, porque você pode SEMPRE reestruturar as tabelas de uma maneira, onde existe apenas um único índice?" Você certamente pode adicionar outra resposta, abordando o ponto que você menciona
ypercubeᵀᴹ