Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Como projetar um modelo de dados que lide com os funcionários atuais e os funcionários previstos?


Eu posso ver algumas razões pelas quais você precisa de duas tabelas para isso:
  • funcionários reais devem ter um nome, um departamento, etc., enquanto os funcionários previstos podem ter esses atributos
  • haverá responsabilidades que apenas funcionários reais podem ter, então você quer poder referenciá-las separadamente

Mas, ao mesmo tempo, você deseja garantir que não haja conflito de IDs nas duas tabelas, porque (espero) os funcionários previstos se tornarão funcionários reais.

A maneira de fazer isso é implementar uma estrutura de supertipo/subtipo. Portanto, você tem uma tabela, EMPLOYEES, que garante chaves primárias únicas e duas tabelas dependentes para funcionários reais e previstos. O uso da coluna tipo é fundamental, pois garante que determinado funcionário apareça apenas em uma subtabela.
create table employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , constraint emp_pk primary key (emp_id)
      , constraint emp_uk unique (emp_id, emp_type)
      , constraint emp_type_ck check (emp_type in ('FORECAST', 'ACTUAL'));

create table actual_employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , name varchar2(30) not null
      , deptno number(2,0) not null
      , sal number(7,2) not null
      , hiredate date not null
      , constraint actemp_pk primary key (emp_id)
      , constraint actemp_type_ck check (emp_type = 'ACTUAL')
      , constraint actemp_emp_fk foreign key (emp_id, emp_type)
                   references emp (emp_id, emp_type) 
                   deferrable initially deferred ;

create table forecast_employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , name varchar2(30) 
      , deptno number(2,0) 
      , sal number(7,2) 
      , predicted_joining_date date
      , constraint foremp_pk primary key (emp_id)
      , constraint foremp_type_ck check (emp_type = 'FORECAST')
      , constraint foremp_emp_fk foreign key (emp_id, emp_type)
                   references emp (emp_id, emp_type) 
                   deferrable initially deferred ;

Portanto, as teclas podem parecer um pouco estranhas. A tabela pai tem uma chave primária e uma chave exclusiva composta. A chave primária garante uma única instância do EMP_ID. A chave exclusiva nos permite construir chaves estrangeiras nas tabelas filhas que fazem referência tanto ao EMP_ID quanto ao EMP_TYPE. Combinado com as restrições de verificação no filho t Isso ocorre porque eles fazem referência à chave exclusiva na tabela pai em vez de sua chave primária. Esse arranjo garante que um empregado possa estar em FORECAST_EMPLOYEES ou ACTUAL_EMPLOYEES, mas não em ambos.

As chaves estrangeiras são adiáveis ​​para permitir a conversão de funcionários previstos em funcionários reais. Isso requer três atividades:
  1. excluindo o registro de FORECAST_EMPLOYEES
  2. inserindo um registro em ACTUAL_EMPLOYEES
  3. alterando o EMP_TYPE (mas não o EMP_ID) em EMPLOYEES.

Sincronizar as ações 2 e 3 é mais fácil com restrições adiadas.

Além disso, observe que outras restrições de chave estrangeira que fazem referência a EMPLOYEES devem usar a chave primária em vez da chave exclusiva. Se o relacionamento se preocupa com o tipo de funcionário, provavelmente deve ser vinculado às tabelas filhas.

Bem-vindo ao mundo da modelagem de dados. É uma grande dor de cabeça. Porque tentar encaixar a realidade confusa em um modelo de dados limpo é difícil :você precisa de requisitos claros para acertar e entender o que é mais importante para que você possa fazer concessões sensatas.

Propus uma abordagem de supertipo/subtipo com base em sua outra pergunta e porque parece ser a melhor maneira de lidar com dois conjuntos de dados:funcionários reais e funcionários fictícios. Acho que esses dois grupos precisam ser tratados de forma diferente. Por exemplo, eu insistiria em que os gerentes fossem funcionários de verdade. Isso é fácil de fazer com uma restrição de integridade contra ACTUAL_EMPLOYEES e muito mais difícil de conseguir com uma única tabela que contém os dois tipos de funcionários.

Claro que ter duas tabelas significa possivelmente gerar mais trabalho no que diz respeito à sincronização de suas estruturas. E daí? É bastante trivial, pois é pouco mais trabalhoso escrever duas instruções ALTER TABLE do que uma. Além disso, é bem possível que a nova coluna se aplique apenas a funcionários reais e não tenha significado para prever funcionários (por exemplo, EARNED_COMMISSION, LAST_REVIEW_RATING). Nesse sentido, ter tabelas separadas torna o modelo de dados mais preciso.

No que diz respeito à duplicação de tabelas dependentes, como Ollie aponta, isso é um mal-entendido. As tabelas que se aplicam a todos os funcionários, independentemente de sua atualidade, devem fazer referência à tabela EMPLOYEES e não a seus filhos.

Finalmente, não entendo por que manter dados históricos é mais difícil com duas tabelas do que com uma. A maior parte do código de registro no diário deve ser totalmente gerado a partir do dicionário de dados.

Existem três tabelas:
  • EMPLOYEES - uma tabela mestra para garantir EMP_IDs exclusivos
  • ACTUAL_EMPLOYEES - uma tabela filha para pessoas que trabalham para sua empresa
  • FORECAST_EMPLOYEES - uma tabela filha para pessoas que você espera recrutar para sua empresa

Lembre-se de que estou fazendo suposições sobre sua lógica de negócios a partir dos poucos detalhes que você forneceu.

Agora me parece que as pessoas que ainda não trabalham para sua empresa não devem ter nenhuma atividade associada. Nesse cenário, você teria uma tabela, EMPLOYEE_ACTIVITIES, que é filha de ACTUAL_EMPLOYEES.

Mas talvez você realmente tenha atividades para pessoas que não existem. Então aqui está uma escolha:uma mesa ou duas? O design de uma tabela tem EMPLOYEE_TASKS como filho da tabela principal EMPLOYEES. O design de duas tabelas tem ACTUAL_EMPLOYEE_TASKS e FORECAST_EMPLOYEE_TASKS como filhos das tabelas ACTUAL_EMPLOYEES e FORECAST_EMPLOYEES, respectivamente.

Qual design é o correto depende se você precisa impor regras relacionadas à atribuição de tarefas. Por exemplo, sua empresa pode ter uma regra que afirma que apenas pessoas reais podem contratar novos funcionários. Portanto, seria útil ter um modelo que permitisse apenas que tarefas de recrutamento fossem atribuídas a ACTUAL_EMPLOYEES.

Ok, adicionei colunas de data às duas tabelas. Isso permitirá que você execute o relatório desejado.