tablas - relacion recursiva base de datos sql
Diseño de base de datos para una relación recursiva. (5)
Considere este caso donde estoy tratando de modelar una base de datos para una empresa:
- Entidades:
Employees
,Managers
,Departments
. - Un
Employee
trabaja en solo 1Department
mientras que unDepartment
puede tener muchosEmployees
trabajando en él. - Un
Manager
puede administrar solo 1Department
y, de manera similar, unDepartment
puede tener solo 1Manager
. - Un
Manager
supervisa a muchosEmployees
, pero unEmployee
solo es supervisado por unManager
.
Ahora tengo 2 formas de modelar esto:
Primera solución:
Consideraré que la entidad Manager
hereda de la entidad Employee
, considerando que mantendré los datos que son exclusivos de los Gerentes (por ejemplo, Bonificación y Estado).
Como la relación entre
Department
yEmployee
es1:N
, colocaré laDepartment Id
delDepartment Id
como una clave externa en la tabla deEmployee
para la relación deWorks
.Dado que la relación entre el
Department
y elManager
es1:1
, colocaré laDepartment Id
delDepartment Id
como una clave externa en la tabla delManages
para la relación de losManages
.
Problema: ¿Cómo puedo representar la relación recursiva entre el Manager
y el Employee
?
Segunda solución:
Consideraré que la entidad Manager
no es necesaria, ya que otros Employees
también pueden tener una Bonus
y Status
. (En realidad agregué estos 2 atributos solo para ver cómo modelarlos en ambos casos)
- Como la relación entre
Department
yEmployee
es1:N
, colocaré laDepartment Id
delDepartment Id
como una clave externa en la tabla deEmployee
para la relación deWorks
. - Dado que la relación entre
Employee
yManager
es1:N
, pondré laEmployee Id
como clave externa en la tabla deEmployee
para la relación deSupervises
y la llamaréManager Id
.
Problema: ¿Cómo puedo representar la relación entre el Manager
y el Department
?
Preguntas:
- ¿Hay errores obvios tanto en el diseño como en el diseño?
- ¿Cómo resolver cada problema en ambos casos?
- ¿Hay una solución mejor que estas dos?
¿Qué tal si te quedas con el segundo diseño y tienes una pseudo-relación?
Supongo que va a tener una columna department_id
en la entidad Employee para vincular la relación entre las entidades Employee y Department. Si podemos asumir que no habrá una jerarquía de gerentes (gerentes de gerentes) podemos imponer una pseudo-relación entre las dos tablas donde Department_ID
para gerentes ( Manager_ID
es nulo) representa el departamento que manejan.
Siempre que lo documente claramente, creo que sería un enfoque eficiente en el uso del espacio ya que ya tendría una columna FK ( department_id
) en la entidad del Empleado que hace referencia a la entidad del Departamento.
Creo que esta es la mejor solución:
Un gerente es un empleado que maneja un departamento. La relación recursiva que puede obtener por el siguiente flujo:
El empleado tiene un departamento Un departamento tiene un empleado como gerente
Tal vez sea útil darle a la tabla de empleados una columna EmployeeType para definir el rol.
Mi opinión:
Tabla Persona donde agregará la información para empleados y gerentes, los gerentes también son seres humanos, ¿saben? :), y tiene un campo managerId para vincular al Id del administrador.
Mesa de departamento con la información del departamento.
y, si el empleado puede pertenecer a más de un departamento, cree una tabla employee_department para relacionarlos. Si un empleado puede pertenecer a un solo departamento y no necesita más información en la relación, agregue un campo departmentID en la tabla Empleado.
Probablemente iría con algo como:
Este modelo tiene las siguientes características:
- El gerente "hereda" al empleado.
- Para representar a un empleado, inserte una sola fila en EMPLEADO.
- Para representar a un administrador, inserte una fila en EMPLEADO y una fila en ADMINISTRADOR.
- Un departamento puede tener varios empleados.
- Cada departamento tiene exactamente 1 gerente y cada gerente maneja 0 o 1 departamentos.
- Un supervisor puede ser un empleado ordinario o un gerente.
- Los departamentos no están obligados a "coincidir":
- Un supervisor puede trabajar en diferentes departamentos del empleado supervisado.
- Un gerente puede gestionar diferentes departamentos desde donde trabaja.
- Si un supervisor es gerente, entonces los departamentos que administra, los departamentos en los que trabaja y los departamentos de sus empleados supervisados pueden ser diferentes.
NOTA: Si su DBMS no admite restricciones diferidas, querrá que el DEPARTMENT.MANAGER_ID sea NULABLE, para romper el ciclo que de otra manera le impediría insertar los nuevos datos.
Si se requiere que los departamentos coincidan, entonces emplearía una técnica específica de DBMS (como activadores o restricciones "especiales"), o "propagaría" el DEPARTMENT_ID en la PK de los empleados. Esta propagación es lo que en última instancia permite el emparejamiento:
Dado que EMPLOYEE_ID debe ser globalmente único, no puede permanecer en la clave compuesta junto con DEPARTMENT_ID. Por lo tanto, hacemos que sea una clave alternativa y en su lugar usamos el sustituto EMPLOYEE_NO en el PK.
Este modelo le impide tener un gerente que administra un departamento y trabaja en otro, o un supervisor que supervisa a los empleados de un departamento diferente.
En caso de que no esté familiarizado con el símbolo ...
... denota una "categoría". En este contexto, puede interpretarlo simplemente como una relación "1 a 0 o 1" entre EMPLEADO y ADMINISTRADOR.
Sin entrar en detalles, le aseguro que la solución Empleado / Gerente / Departamento es, a largo plazo, una fuente de disgusto (al principio) y luego un PITA real (más adelante) para las personas a cargo de mantener la base de datos y / o desarrollando su interfaz. Así que te aconsejo que te limites a tu segunda propuesta.
Con respecto a la relación gerente / departamento, tiene principalmente dos formas de representar esta relación. Ambas soluciones le autorizan a mantener su relación recursiva de "Gerente administra empleado" además de una relación de "Gerente gerente Departamento" que puede implementar de la siguiente manera:
1 - primera / forma simple: agregue una identificación de gerente / empleado en la tabla de su departamento. Este campo es, por supuesto, una clave foránea para la tabla de empleados.
Solución de 2 segundos / más compleja: agregue una tabla de "administrador" con los siguientes campos:
Manager id (PK, surrogate)
Department id (FK)
Employee id (FK)
beginningDate
endingDate
dónde almacenará el historial de gestión: quién, para qué departamento, desde cuándo, hasta cuándo
En este caso, no olvide agregar algo de lógica (activador o control del lado del cliente) para traducir sus reglas comerciales, ya que solo puede tener un administrador por un período específico y un departamento específico, ningún departamento puede quedarse más que ... sin gerente, etc.
EDITAR:
3: una solución más rica sería una generalización de mi segunda propuesta y le permitirá realizar un seguimiento de la carrera de todos en la empresa. Puede hacerlo con una tabla de ''trabajos en'', como esta (como lo llamamos aquí una tabla de ''posición'', mantendré la misma terminología aquí:
Position id (PK, surrogate)
Department id (FK)
Employee id (FK)
Position Level (FK)
beginningDate
endingDate
Donde ''nivel de posición'' lleva a otra tabla que contiene las diferentes posiciones que pueden existir en un departamento, una de ellas es, por supuesto, la posición de ''gerente''.
Esta propuesta está más cerca de lo que se usa en la base de datos y el software de recursos humanos, y es posible que no necesite una solución tan compleja. Pero tenga en cuenta que dividir a los seres humanos en varias tablas SIEMPRE es un error.
EDITAR: siguiendo tu comentario ...
Para aclarar las cosas, le aconsejo que ajuste los nombres de sus campos. Te propondría que tengas los siguientes campos:
Tbl_Employee.id_EmployeeManager
y
Tbl_Department.id_DepartmentManager
Al hacer esto, nosotros (o cualquier desarrollador) entenderemos inmediatamente que id_EmployeeManager participa en la relación recursiva entre las personas, mientras que id_DepartmentManager participa en la relación entre las personas y el departamento.
De vuelta a sus preguntas, y de acuerdo a mí, no debe crear el siguiente enlace:
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_EmployeeManager
Al hacerlo, quiere decir que alguien no puede ser gerente de departamento a menos que ya esté administrando empleados. ¿Qué pasa con los departamentos con un solo empleado? ¿Qué pasa con las personas nombradas gerentes de un departamento de nueva creación, donde aún no se asigna ningún empleado? No funciona. El enlace correcto debe ser:
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_Employee
Por supuesto, podría agregar algunas reglas de negocios que digan, por ejemplo, que "un empleado que administra un departamento solo puede ser un administrador" (id_Employee existe en algún lugar como id_EmployeeManager) o "un empleado que administra un departamento no puede tener un gerente (donde id_EmployeeManager para este empleado es nulo ...). Pero estas son solo reglas de negocios. Su modelo de datos está limpio para aceptar todas las reglas siempre que se respete la regla básica, que es que un departamento es administrado por un empleado.