Diseño de base de datos: dos relaciones de 1 a muchas para la misma tabla


20

Tengo que modelar una situación en la que tengo una tabla Chequing_Account (que contiene el presupuesto, el número iban y otros detalles de la cuenta) que tiene que estar relacionada con dos tablas diferentes Persona y Corporación, que pueden tener 0, 1 o muchas cuentas de cheques.

En otras palabras, tengo dos relaciones de 1 a muchos con la misma tabla Chequing account

Me gustaría escuchar soluciones para este problema que respeten los requisitos de normalización. La mayoría de las soluciones que he escuchado son:

1) encontrar una entidad común a la que pertenezcan Persona y Corporación y crear una tabla de enlaces entre esta y la tabla Chequing_Account, esto no es posible en mi caso e incluso si lo fuera, quiero resolver el problema general y no esta instancia específica.

2) Cree dos tablas de enlaces PersonToChequingAccount y CorporationToChequingAccount que relacionen las dos entidades con las cuentas de cheques. Sin embargo, no quiero que dos Personas tengan la misma cuenta de cheques, ¡y no quiero que una persona física y una Corporación compartan una cuenta de cheques! ver esta imagen

http://i41.tinypic.com/35i6kbk.png

3) Crear dos claves foráneas en Chequing Account que apunten a Corporación y Persona física, sin embargo, exigiría que una Persona y una Compañía puedan tener muchas cuentas de cheques, sin embargo, tendría que asegurarme manualmente de que para cada fila de ChequingAccount no ambas relaciones apuntan a Corporación y persona física porque una cuenta de cheques es de una corporación o de una persona física. ver esta imagen

http://i40.tinypic.com/1rpv9z.png

¿Hay alguna otra solución más limpia para este problema?


¿Has pensado en tener, por ejemplo, un OwnerTypeIDen la ChecquingAccountmesa, con 1=Corporationy 2=NaturalPerson? De esa manera solo necesita uno OwnerIDen la ChecquingAccounttabla, que puede indexar junto con OwnerTypeID.
RoKa

No solo necesito saber si es una corporación o una persona física, sino también conocer la identificación respectiva, ¡así que necesito un número de identificación y no solo un valor de 1 o 2! La solución 3 es lo que encontré aquí. Tengo dos columnas con identificadores para corporación o persona física
Dendini

2
Sí, la solución es una opción válida. En la mayoría de los DBMS, puede exigir que solo uno de los dos FK esté "activo" con una restricción de verificación: CHECK (CorporationID IS NOT NULL AND NaturalPersonID IS NULL OR CorporationID IS NULL AND NaturalPersonID IS NOT NULL)aunque prefiero la solución 1 (pero esa soy yo). Es mucho más "limpio".
ypercubeᵀᴹ

Sí, lo entiendo, pero podría tener en la ChecquingAccounttabla un registro de OwnerTypeID=1e OwnerID=123, indicando que es un tipo Corporation, por lo tanto, ID 123en la Corporationtabla. El OwnerTypeID le dice qué tabla, y el OwnerID le dice la ID en esa tabla.
RoKa

1
¿Cómo es imposible la opción # 1? La palabra "Corporación" básicamente significa "un negocio que es legalmente una persona", después de todo. Llámalo una Customersmesa.
Jon of All Trades

Respuestas:


15

Las bases de datos relacionales no están construidas para manejar esta situación perfectamente. Debe decidir qué es lo más importante para usted y luego hacer sus compensaciones. Tienes varios objetivos:

  • Mantener la tercera forma normal
  • Mantener integridad referencial
  • Mantenga la restricción de que cada cuenta pertenece a una corporación o persona física.
  • Preserve la capacidad de recuperar datos de manera simple y directa

El problema es que algunos de estos objetivos compiten entre sí.

Solución de subtipificación
Puede elegir una solución de subtipificación en la que cree un supertipo que incorpore corporaciones y personas. Este supertipo probablemente tendría una clave compuesta de la clave natural del subtipo más un atributo de partición (por ejemplo customer_type). Esto está bien en lo que respecta a la normalización y le permite hacer cumplir la integridad referencial, así como la restricción de que las corporaciones y las personas se excluyan mutuamente. El problema es que esto hace que la recuperación de datos sea más difícil, porque siempre tiene que bifurcarse customer_typecuando se une la cuenta al titular de la cuenta. Esto probablemente significa usar UNIONy tener muchos SQL repetitivos en su consulta.

Solución de dos claves extranjeras
Puede elegir una solución en la que mantenga dos claves extranjeras en la tabla de su cuenta, una para la corporación y otra para la persona. Esta solución también le permite mantener integridad referencial, normalización y exclusividad mutua. También tiene el mismo inconveniente de recuperación de datos que la solución de subtipado. De hecho, esta solución es igual que la solución de subtipado, excepto que llega al problema de bifurcar su lógica de unión "antes".

Sin embargo, muchos modeladores de datos considerarían esta solución inferior a la solución de subtipado debido a la forma en que se aplica la restricción de exclusividad mutua. En la solución de subtipado, utiliza claves para imponer la exclusividad mutua. En las dos soluciones de clave externa, utiliza una CHECKrestricción. Conozco algunas personas que tienen un sesgo injustificado contra las restricciones de verificación. Estas personas preferirían la solución que mantiene las restricciones en las claves.

Solución de atributos de particionamiento "desnormalizados"
Hay otra opción en la que mantiene una sola columna de clave externa en la tabla de la cuenta de cheques y usa otra columna para indicarle cómo interpretar la columna de clave externa (RoKa'sOwnerTypeIDcolumna). Esto esencialmente elimina la tabla de supertipo en la solución de subtipado al desnormalizar el atributo de partición en la tabla secundaria. (Tenga en cuenta que esto no es estrictamente "desnormalización" según la definición formal, porque el atributo de partición es parte de una clave primaria). Esta solución parece bastante simple ya que evita tener una tabla adicional para hacer más o menos lo mismo y reduce el número de columnas de clave externa a uno. El problema con esta solución es que no evita la ramificación de la lógica de recuperación y, además, no le permite mantener la integridad referencial declarativa . Las bases de datos SQL no tienen la capacidad de administrar una sola columna de clave externa para una de varias tablas principales.

Solución de dominio de clave primaria compartida
Una forma en que las personas a veces se ocupan de este problema es usar un solo grupo de ID para que no haya confusión para una ID dada si pertenece a un subtipo u otro. Esto probablemente funcionaría de manera bastante natural en un escenario bancario, ya que no va a emitir el mismo número de cuenta bancaria tanto para una corporación como para una persona física. Esto tiene la ventaja de evitar la necesidad de un atributo de partición. Puede hacer esto con o sin una tabla de supertipo. El uso de una tabla de supertipo le permite usar restricciones declarativas para imponer la unicidad. De lo contrario, esto debería hacerse cumplir procesalmente. Esta solución está normalizada, pero no le permitirá mantener la integridad referencial declarativa a menos que mantenga la tabla de supertipo. Todavía no hace nada para evitar una lógica de recuperación compleja.

Por lo tanto, puede ver que no es realmente posible tener un diseño limpio que siga todas las reglas, al mismo tiempo que simplifica la recuperación de sus datos. Tienes que decidir dónde van a ser tus compensaciones.


Mi solución # 2 ¿a cuál de sus cuatro grupos pertenece? La "Solución de atributo de particionamiento desnormalizado" no me queda del todo clara ..
dendini

@dendini: su solución número 2 no encaja con ninguna de las soluciones que describí. Esto se debe a que no cumple con el requisito de una cuenta que pertenezca a una entidad legal. La forma en que ha definido las claves primarias de las tablas intermedias, son intersecciones de muchos a muchos. Si las claves primarias fueran justas corporation_id y person_identonces esencialmente tendría la solución de subtipado, excepto que la tabla de supertipo se habría dividido en dos y la clave externa se habría invertido, por lo que las personas no podrían tener varias cuentas. Este tipo de derrota el propósito.
Joel Brown

Gran explicación @JoelBrown, ¿cuáles son las implicaciones de rendimiento de la solución "Dos claves externas", en términos de consulta? Además, considerando que en lugar de 2, puede haber 6 o más claves foráneas: ¿aún recomendaría este enfoque o preferiría inclinarse por uno diferente?
Amadeo Gallardo

1
@AmadeoGallardo La respuesta es "depende". La consulta contra una clave siempre es bastante eficiente, ya que generalmente puede contar con un escaneo de índice al menos, si no una búsqueda, y estas son operaciones rápidas. El problema se convierte cuando consulta en ambas claves en la solución de dos claves externas . Aquí le está pidiendo al optimizador de consultas que realice una operación u otra. En el mejor de los casos, esto duplicará el costo de la consulta, generalmente un poco peor, ya que debe consultar una tecla, luego la otra y luego combinar los resultados.
Joel Brown

@JoelBrown Las versiones futuras de SQL desnormalizadas deberían permitir este enfoque al permitir la definición de una clave externa compuesta basada en dos columnas RefIDy RefTabledonde RefTablehay una identificación fija que identifica la tabla de destino. Hay muchos casos de uso para este tipo de clave y es demasiado para mantener 10 o más tablas de asociación / subtipo para hacer cumplir la integridad. Para esos casos, creé esto keyyo mismo.
djmj
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.