CodeGym /Cursos /SQL SELF /Verificação de integridade dos dados

Verificação de integridade dos dados

SQL SELF
Nível 20 , Lição 2
Disponível

Hoje vamos começar a entender como as foreign keys ajudam a gente a cuidar da integridade dos dados e evitar problemas clássicos com dados inconsistentes ou errados.

Primeiro de tudo, vamos entender o que a gente quer dizer com "integridade dos dados". Imagina que você tem uma tabela de pedidos (orders) e uma tabela de clientes (customers). Se um pedido tem um cliente que não existe na tabela de clientes, isso é uma quebra de integridade. O importante é que todos os dados nas tabelas relacionadas estejam em sintonia lógica.

Integridade dos dados significa:

  • Nada de referências "vazias": se a gente faz referência a algo em outra tabela, esse "algo" sempre tem que existir.
  • Resistência a erros de modificação: se a gente apaga um valor de uma tabela que está sendo referenciado em outro lugar, o banco de dados tem que avisar a gente ou lidar com isso de forma correta.

É pra isso que a gente usa foreign keys no PostgreSQL.

Como as foreign keys garantem a integridade dos dados?

Quando você cria uma foreign key numa tabela, o PostgreSQL automaticamente checa:

  1. Se os dados existem na tabela mãe. Antes de inserir ou atualizar um registro, o PostgreSQL verifica se a foreign key informada existe na tabela relacionada.
  2. Remoção ou alteração de dados. Antes de apagar ou atualizar um registro na tabela mãe, o PostgreSQL checa se tem registros na tabela filha que fazem referência a ele.

As foreign keys são tipo um "guarda". Elas não deixam passar dados errados e garantem que as tabelas vão interagir conforme as regras que você definiu.

Exemplo: integridade dos dados nas tabelas de estudantes e cursos

Vamos supor que a gente tem duas tabelas — students e courses. Cada estudante pode se inscrever em vários cursos. Pra representar essa relação, a gente usa a tabela enrollments. Agora imagina alguém tentando inscrever um estudante num curso que não existe.

Passo 1. Vamos criar três tabelas relacionadas:

CREATE TABLE students (
    student_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    title TEXT NOT NULL
);

CREATE TABLE enrollments (
    enrollment_id SERIAL PRIMARY KEY,
    student_id INT REFERENCES students(student_id),
    course_id INT REFERENCES courses(course_id)
);

Aqui:

  • Na tabela enrollments a gente deixou claro as foreign keys student_id e course_id, que apontam pros primary keys das tabelas students e courses.

Checagens comuns de integridade dos dados

  1. Checagem ao inserir dados

Se a gente tentar inserir na tabela enrollments um registro com student_id ou course_id que não existem, vai dar erro.

Exemplo:

INSERT INTO enrollments (student_id, course_id)
VALUES (999, 1); -- Erro! Estudante com ID 999 não existe.

Mensagem de erro:

ERROR:  insert or update on table "enrollments" violates foreign key constraint "enrollments_student_id_fkey"
DETAIL:  Key (student_id)=(999) is not present in table "students".
  1. Checagem ao deletar dados

Vamos tentar apagar um registro da tabela mãe que está sendo referenciado.

Exemplo:

INSERT INTO students (name) VALUES ('Alice');
INSERT INTO courses (title) VALUES ('Mathematics');

INSERT INTO enrollments (student_id, course_id)
VALUES (1, 1); -- Inserção bem-sucedida

DELETE FROM students WHERE student_id = 1; -- Erro, porque o estudante ainda está inscrito no curso!

Mensagem de erro:

ERROR:  update or delete on table "students" violates foreign key constraint "enrollments_student_id_fkey" on table "enrollments"
DETAIL:  Key (student_id)=(1) is still referenced from table "enrollments".

Pra deletar registros corretamente nesses casos, a gente usa estratégias como CASCADE, SET NULL ou RESTRICT, que já falamos antes.

Exemplos de uso de foreign keys pra checar integridade

Exemplo 1: Proteção automática contra dados errados

Com foreign keys, o PostgreSQL automaticamente impede a inserção de dados "inexistentes":

-- Vamos tentar adicionar estudantes que não existem num curso:
INSERT INTO enrollments (student_id, course_id)
VALUES (42, 1); -- Erro! Estudante com ID 42 não existe.

Isso garante que um estudante não vai conseguir se inscrever num curso se ele não existir na tabela students.

Exemplo 2: Deletando dados com ON DELETE CASCADE

Se a foreign key estiver configurada pra deletar em cascata ON DELETE CASCADE, quando você apagar um registro na tabela mãe, os dados relacionados na tabela filha também vão ser apagados.

ALTER TABLE enrollments DROP CONSTRAINT enrollments_student_id_fkey; -- Removendo a foreign key antiga

ALTER TABLE enrollments
ADD CONSTRAINT enrollments_student_id_fkey FOREIGN KEY (student_id)
REFERENCES students(student_id) ON DELETE CASCADE;

DELETE FROM students WHERE student_id = 1; -- Agora também apaga os registros da tabela enrollments

Exemplo 3: Lidando com alterações usando ON UPDATE

Se a foreign key estiver configurada com ON UPDATE CASCADE, quando você mudar o valor na tabela mãe, o PostgreSQL atualiza automaticamente os dados na tabela filha.

-- Vamos configurar a foreign key pra que mudanças no primary key da mãe sejam refletidas na filha:
ALTER TABLE enrollments DROP CONSTRAINT enrollments_student_id_fkey;

ALTER TABLE enrollments
ADD CONSTRAINT enrollments_student_id_fkey FOREIGN KEY (student_id)
REFERENCES students(student_id) ON UPDATE CASCADE;

-- Mudando o id do estudante:
UPDATE students SET student_id = 10 WHERE student_id = 1;

-- Agora na tabela enrollments o student_id também vai ser atualizado pra 10.

Testando a integridade dos dados

Sempre vale a pena testar como as configurações da foreign key se comportam em diferentes cenários:

  1. Tenta inserir dados com student_id ou course_id errado.
  2. Deleta dados de students e vê como a tabela enrollments reage.
  3. Muda dados na tabela students e confere se os registros relacionados foram atualizados.

Peculiaridades ao trabalhar com foreign keys

Às vezes rolam situações que podem confundir:

  • Falta de índice. Se a tabela mãe (students, por exemplo) não tem o campo referenciado indexado, o PostgreSQL pode "tentar" trabalhar mais devagar. Por isso, é importante que o primary key da tabela mãe sempre seja um índice.
  • Referências cíclicas. Se duas tabelas apontam uma pra outra, pode dar trabalho na hora de inserir dados. Nesses casos, o design tem que ser mais cuidadoso.
  • Deletar todos os registros. Se você precisa deletar tudo usando delete em cascata, tem que prestar atenção nos dados da tabela filha pra não ter surpresas.

Pra evitar esses problemas, é importante planejar bem as tabelas e testar as regras de relacionamento antes de usar no banco de dados de verdade.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION