Database
 sql >> Base de Dados >  >> RDS >> Database

Correção e Restrições


Introdução


Armazenar dados é uma coisa; armazenamento significativo, útil, correto dados é outra bem diferente. Embora o significado e a utilidade sejam qualidades subjetivas, pelo menos a correção pode ser definida e imposta logicamente. Os tipos já garantem que os números sejam números e as datas sejam datas, mas não podem garantir que o peso ou a distância sejam números positivos ou impedir que os intervalos de datas se sobreponham. Restrições de tupla, tabela e banco de dados aplicam regras aos dados armazenados e rejeitam valores ou combinações de valores que não são aprovados.

As restrições não tornam outras técnicas de validação de entrada inúteis de forma alguma, mesmo quando testam as mesmas asserções. O tempo gasto tentando e não armazenando dados inválidos é tempo perdido. Mensagens de violação, como assert em sistemas e linguagens de programação de aplicativos, apenas revela o primeiro problema com o primeiro registro candidato com muito mais detalhes do que qualquer pessoa não envolvida imediatamente com as necessidades do banco de dados. Mas no que diz respeito à exatidão dos dados, as restrições são lei, para o bem ou para o mal; qualquer outra coisa é conselho.


Em Tuplas:Não Nulo, Padrão e Verificado


As restrições não nulas são a categoria mais simples. Uma tupla deve ter um valor para o atributo restrito, ou dito de outra forma, o conjunto de valores permitidos para a coluna não inclui mais o conjunto vazio. Nenhum valor significa que não há tupla:a inserção ou atualização é rejeitada.

Proteger contra valores nulos é tão fácil quanto declarar column_name COLUMN_TYPE NOT NULL em CREATE TABLE ou ADD COLUMN . Valores nulos causam categorias inteiras de problemas entre o banco de dados e os usuários finais, portanto, definir reflexivamente restrições não nulas em qualquer coluna sem um bom motivo para permitir nulos é um bom hábito.

O fornecimento de um valor padrão se nada for especificado (por omissão ou um NULL explícito ) em uma inserção ou atualização nem sempre é considerada uma restrição, pois os registros candidatos são modificados e armazenados em vez de rejeitados. Em muitos SGBDs, os valores padrão podem ser gerados por uma função, embora o MySQL não permita funções definidas pelo usuário para esta finalidade.

Qualquer outra regra de validação que dependa apenas dos valores dentro de uma única tupla pode ser implementada como um CHECK limitação. De certa forma, NOT NULL em si é um atalho para CHECK (column_name IS NOT NULL); a mensagem de erro recebida em violação faz a maior diferença. CHECK , no entanto, pode aplicar e impor a verdade de qualquer predicado booleano sobre uma única tupla. Por exemplo, uma tabela que armazena localizações geográficas deve CHECK (latitude >= -90 AND latitude < 90) , e da mesma forma para longitude entre -180 e 180 -- ou, se disponível, use e valide uma GEOGRAPHY tipo de dados.


Nas tabelas:exclusivo e exclusão


As restrições de nível de tabela testam as tuplas umas contra as outras. Em uma restrição exclusiva, apenas um registro pode ter um determinado conjunto de valores para as colunas restritas. A nulidade pode causar problemas aqui, pois NULL nunca é igual a qualquer outra coisa, até e incluindo NULL em si. Uma restrição exclusiva em (batman, robin) portanto, permite cópias infinitas de qualquer Batman sem Robin.

As restrições de exclusão são suportadas apenas no PostgreSQL e no DB2, mas preenchem um nicho muito útil:elas podem evitar sobreposições. Especifique os campos restritos e as operações pelas quais cada um será avaliado, e um novo registro só será aceito se nenhum registro existente for comparado com sucesso com cada campo e operação. Por exemplo, um schedules tabela pode ser configurada para rejeitar conflitos:
-- text, int, etc. comparisons in exclusion constraints require this-- Postgres extensionCREATE EXTENSION btree_gist;CREATE TABLE schedules (  schedule_id SERIAL NOT NULL PRIMARY KEY,  room_number TEXT NOT NULL,  -- a range of TIMESTAMP WITH TIME ZONE provides both start and end  duration TSTZRANGE,  -- table-level constraints imply an index, since otherwise they'd  -- have to search the entire table to validate a candidate record;  -- GiST (generalized search tree) indexes are usually used in  -- Postgres  EXCLUDE USING GIST (    room_number WITH =,    duration WITH &&  ));INSERT INTO schedules (room_number, duration)VALUES ('32A', '[2020-08-20T10:00:00Z,2020-08-20T11:00:00Z)');-- the same time in a different room: acceptedINSERT INTO schedules (room_number, duration)VALUES ('32B', '[2020-08-20T10:00:00Z,2020-08-20T11:00:00Z)');-- a half-hour overlap for an already-scheduled room: rejectedINSERT INTO schedules (room_number, duration)VALUES ('32A', '[2020-08-20T10:30:00Z,2020-08-20T11:30:00Z)');

Operações de upsert como ON CONFLICT do PostgreSQL cláusula ou ON DUPLICATE KEY UPDATE do MySQL use uma restrição de nível de tabela para detectar conflitos. E como restrições não nulas podem ser expressas como CHECK restrições, uma restrição única pode ser expressa como uma restrição de exclusão na igualdade.


A chave primária


As restrições exclusivas têm um caso especial particularmente útil. Com uma restrição adicional não nula na coluna ou colunas exclusivas, cada registro na tabela pode ser identificado individualmente por seus valores para as colunas restritas, que são chamadas coletivamente de chave . Várias chaves candidatas podem coexistir em uma tabela, como users às vezes ainda tendo um email exclusivo e não nulo distinto s e username s; mas declarar uma chave primária estabelece um único critério pelo qual os registros são conhecidos publicamente e exclusivamente. Alguns RDBMSs até organizam linhas nas páginas pela chave primária, chamada para esse propósito de índice clusterizado , para tornar a pesquisa por valores de chave primária o mais rápido possível.

Existem dois tipos de chave primária. Uma chave natural é definida em uma coluna ou colunas "naturalmente" incluídas nos dados da tabela, enquanto uma chave substituta ou sintética é inventada apenas com o objetivo de se tornar a chave. Chaves naturais requerem cuidado - mais coisas podem mudar do que os designers de banco de dados geralmente acreditam, de nomes a esquemas de numeração. Uma tabela de pesquisa contendo nomes de países e regiões pode usar seus respectivos códigos ISO 3166 como uma chave primária natural segura, mas um users tabela com uma chave natural baseada em valores mutáveis ​​como nomes ou endereços de e-mail convida a problemas. Em caso de dúvida, crie uma chave substituta.

Se uma chave natural abrange várias colunas, uma chave substituta deve sempre ser considerada pelo menos, pois as chaves de várias colunas exigem mais esforço para gerenciar. Se a chave natural for adequada, no entanto, as colunas devem ser ordenadas em especificidade crescente, assim como nos índices:código do país então código de região, e não o inverso.

A chave substituta tem sido historicamente uma única coluna inteira, ou BIGINT onde bilhões serão eventualmente atribuídos. Bancos de dados relacionais podem preencher automaticamente chaves substitutas com o próximo inteiro em uma série, um recurso geralmente chamado de SERIAL ou IDENTITY .

Um contador numérico de incremento automático tem suas desvantagens:adicionar registros com chaves pré-geradas pode causar conflitos e, se os valores sequenciais forem expostos aos usuários, é fácil para eles adivinhar quais outras chaves válidas podem ser. Identificadores Universalmente Exclusivos, ou UUIDs, evitam esses pontos fracos e se tornaram uma escolha comum para chaves substitutas, embora também sejam muito maiores na página do que um simples número. Os tipos de UUID v1 (baseado em endereço MAC) e v4 (pseudorandom) são os mais usados.


No banco de dados:chaves estrangeiras


Os bancos de dados relacionais implementam apenas uma classe de restrição de várias tabelas, o "requisito de subconjunto" ou chave estrangeira. Este único tipo de restrição é o garantidor da integridade referencial , o princípio que protege contra inconsistências entre tabelas e distingue um banco de dados relacional de uma planilha.



Este "diagrama entidade-relacionamento" informal ou ERD mostra o início de um esquema para um banco de dados de bibliotecas e suas coleções e usuários. Cada aresta representa uma relação entre as tabelas que ela conecta. O | glifo indica um único registro em seu lado, enquanto o glifo "pé de galinha" representa vários:uma biblioteca contém muitos livros e tem muitos frequentadores.

Uma chave estrangeira é uma cópia da chave primária de outra tabela, coluna por coluna (um ponto a favor das chaves substitutas:apenas uma coluna para copiar e referenciar), com valores ligando registros nesta tabela a registros "pais" nela. No esquema acima, os books tabela mantém um library_id chave estrangeira para libraries , que contém livros e um author_id para authors , que os escreve. Mas o que acontece se um livro for inserido com um author_id que não existe em authors ?

Se a chave estrangeira não for restrita - ou seja, é apenas outra coluna ou colunas - um livro pode ter um autor que não existe. Este é um problema:se alguém tentar seguir o link entre books e authors , eles acabam em lugar nenhum. Se authors.author_id é um número inteiro serial, também existe a possibilidade de que ninguém perceba até que o espúrio author_id é eventualmente atribuído, e você acaba com uma cópia específica de Don Quixote atribuído primeiro a ninguém conhecido e depois a Pierre Menard, com Miguel Cervantes longe de ser encontrado.

Restringir a chave estrangeira não pode impedir que um livro seja atribuído erroneamente se o author_id incorreto apontar para um registro existente em authors , portanto, outras verificações e testes permanecem importantes. No entanto, o conjunto de valores de chave estrangeira existentes é quase sempre um pequeno subconjunto dos possíveis valores de chave estrangeira, portanto, as restrições de chave estrangeira capturarão e impedirão a maioria dos valores errados. Com uma restrição de chave estrangeira, o Quixote com um autor inexistente será rejeitado em vez de registrado.

É daqui que vem o "Relacional" em "Banco de Dados Relacional"?

h3>
Chaves estrangeiras criam relacionamentos entre tabelas, mas as tabelas como as conhecemos são matematicamente relações entre os conjuntos de valores possíveis para cada atributo. Uma única tupla relaciona um valor da coluna A a um valor da coluna B em diante. O artigo original de E.F. Codd usa "relacional" nesse sentido.

Isso causou uma confusão sem fim e provavelmente continuará a fazê-lo para sempre.



Para Certos Valores de Correto


Há muito mais maneiras pelas quais os dados podem estar incorretos do que as abordadas aqui. As restrições ajudam, mas mesmo elas são tão flexíveis; muitas especificações intratabelas comuns, como um limite de dois ou mais no número de vezes que um valor pode aparecer em uma coluna, só podem ser aplicadas com gatilhos.

Mas também existem maneiras pelas quais a própria estrutura de uma tabela pode levar a inconsistências. Para evitar isso, precisaremos empacotar as chaves primárias e estrangeiras não apenas para definir e validar, mas para normalizar as relações entre as tabelas. Primeiro, porém, mal arranhamos a superfície de como os relacionamentos entre as tabelas definem a estrutura do próprio banco de dados.