INTRODUCCIÓN E INFORMACIÓN RELEVANTE:
El siguiente ejemplo ilustra el problema que enfrento:
El animal tiene una raza, que puede ser un gato o un perro . El gato puede ser siamés o persa . El perro puede ser un pastor alemán o un labrador retriver .
Animal es una entidad fuerte, mientras que su raza es un atributo que puede tener uno de los dos valores ofrecidos (gato o perro). Ambos valores son complejos (he agregado aquí solo el tipo de perro / gato para ilustrar el problema, pero también puede haber el nombre del gato / perro y un montón de otras cosas).
PROBLEMA:
No sé cómo crear tablas relacionales para este ejemplo.
MIS ESFUERZOS PARA RESOLVER EL PROBLEMA:
He intentado dibujar un diagrama ER, usando la notación de Chen, que representa el problema, pero como soy un principiante, no sé si lo hice bien. Esto es lo que tengo:
Pido disculpas si dibujé algo mal, corrígeme si ese es el caso. No deseo simplemente obtener una "solución gratuita" sino también aprender a lidiar con este problema para poder resolverlo por mi cuenta en el futuro.
Lo único que se me ocurre es crear dos tablas separadas, una para gatos y otra para perros. Además, el atributo de raza en la tabla Animal solo almacenaría el valor de un gato o un perro . Algo como esto:
Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >
Realmente tengo un mal presentimiento sobre mi solución y me temo que está mal, de ahí la siguiente pregunta.
PREGUNTAS
- ¿Cómo puedo transformar mi ejemplo en un diagrama ER?
- ¿Cómo transformar ese diagrama ER en tablas relacionales?
Si se requiere más información, deje un comentario y actualizaré mi publicación lo antes posible. También siéntase libre de agregar etiquetas apropiadas ya que soy bastante nuevo aquí.
Gracias.
fuente
Respuestas:
La estructura adecuada para este escenario es un modelo de Subclase / Herencia, y es casi idéntico al concepto que propuse en esta respuesta: Lista de valores ordenada heterogénea .
El modelo propuesto en esta pregunta es en realidad bastante cercano, ya que la
Animal
entidad contiene el tipo (es decirrace
) y las propiedades que son comunes en todos los tipos. Sin embargo, hay dos cambios menores que se necesitan:Elimine los campos Cat_ID y Dog_ID de sus respectivas entidades:
El concepto clave aquí es que todo lo que es una
Animal
, sin tener en cuentarace
:Cat
,Dog
,Elephant
, y así sucesivamente. Dado ese punto de partida, cualquier particularrace
deAnimal
realmente no necesita un identificador separado ya que:Animal_ID
es únicoCat
,Dog
y cualquierrace
entidad adicional agregada en el futuro, por sí mismas, no representan completamente ningún particularAnimal
; que sólo tienen significado cuando se utiliza en combinación con la información contenida en la entidad matriz,Animal
.Por lo tanto, la
Animal_ID
propiedad en elCat
,Dog
, etc entidades es a la vez el PK y la parte posterior FK a laAnimal
entidad.Diferenciar entre tipos de
breed
:El hecho de que dos propiedades compartan el mismo nombre no significa necesariamente que esas propiedades sean las mismas, incluso si el nombre es el mismo implica tal relación. En este caso, lo que realmente tiene es en realidad
CatBreed
yDogBreed
como "tipos" separadosNotas iniciales
VARCHAR
pero si necesita almacenar algo fuera del conjunto ASCII estándar, realmente debería usarloNVARCHAR
.Race
,CatBreed
yDogBreed
) no se incrementan automáticamente (es decir, IDENTITY en términos de T-SQL) porque son constantes de aplicación (es decir, son parte de la aplicación) que son valores de búsqueda estáticos en base de datos y se representan comoenum
s en C # (u otros lenguajes). Si se agregan valores, se agregan en situaciones controladas. Me reservo el uso de campos de incremento automático para los datos del usuario que ingresan a través de la aplicación."Raza" como "Raza" - Enfoque específico
Este primer conjunto de tablas son las tablas de búsqueda / tipos:
Este segundo listado es la principal entidad "Animal":
Este tercer conjunto de tablas son las entidades de subclase complementarias que completan la definición de cada una
Race
deAnimal
:El modelo que usa un
breed
tipo compartido se muestra después de la sección "Notas adicionales".Notas adicionales
breed
parece ser un punto focal para la confusión. Fue sugerido por jcolebrand (en un comentario sobre la pregunta) quebreed
es una propiedad compartida entre los diferentes correos electrónicosrace
, y las otras dos respuestas lo tienen integrado como tal en sus modelos. Sin embargo, esto es un error, porque los valores debreed
no se comparten entre los diferentes valores derace
. Sí, soy consciente de que los otros dos modelos propuestos intentan resolver este problema haciendorace
un padre debreed
. Si bien eso resuelve técnicamente el problema de la relación, no ayuda a resolver la pregunta general de modelado sobre qué hacer con las propiedades no comunes, ni cómo manejar unarace
que no tiene abreed
. Pero, en el caso de que se garantizara que tal propiedad existiera en todosAnimal
s, también incluiré una opción para eso (a continuación).Animal
), orace
s se almacenen en laAnimal
entidad, que es una forma muy plana (y casi no relacional) de representar estos datos. Sí, la gente hace esto todo el tiempo, pero significa tener muchos campos NULL por fila para las propiedades que no están destinadas a ese particularrace
Y saber qué campos por fila están asociados con el particularrace
de ese registro.race
deAnimal
en el futuro que no tienebreed
como propiedad. E incluso si TODOSAnimal
tienen unabreed
, eso no cambiaría la estructura debido a lo que se ha señalado anteriormentebreed
: esobreed
depende derace
(es decir,breed
porqueCat
no es lo mismo quebreed
paraDog
)."Raza" como enfoque de propiedad común / compartida
Tenga en cuenta:
El SQL a continuación se puede ejecutar en la misma base de datos que el modelo presentado anteriormente:
Race
mesa es igualBreed
mesa es nuevaAnimal
tablas han sido agregadas con un2
Breed
siendo una propiedad ahora común, no parece correcto no haberloRace
notado en la entidad principal / principal (incluso si es técnicamente correcto desde el punto de vista relacional). Entonces, ambosRaceID
yBreedID
están representados enAnimal2
. Para evitar una falta de coincidencia entre loRaceID
anotado enAnimal2
y loBreedID
que es para un diferenteRaceID
, he agregado un FK en ambosRaceID, BreedID
que hace referencia a una RESTRICCIÓN ÚNICA de esos campos en laBreed
tabla. Por lo general, desprecio señalar un FK a una RESTRICCIÓN ÚNICA, pero esta es una de las pocas razones válidas para hacerlo. Una RESTRICCIÓN ÚNICA es lógicamente una "Clave alternativa", que la hace válida para este uso. Tenga en cuenta también que laBreed
tabla todavía tiene un PK en soloBreedID
.BreedID
que se repita lo mismo en diferentes valores deRaceID
.BreedID
, por lo que aún debería ser posible hacer referencia a un valor específico deBreed
sin tenerRaceID
disponible.Breed
(y es por eso que prefiero las tablasRace
específicasBreed
).Breed
tienen las mismas propiedades. No hay una manera fácil en este modelo de tener propiedades dispares entreDog
"razas" yElephant
"razas". Sin embargo, todavía hay una manera de hacerlo, que se observa en la sección "Edición final".Breed
en más de una carrera. No estoy seguro de si es deseable hacerlo (o tal vez no en el concepto de animales, pero posiblemente en otras situaciones que estarían usando este tipo de modelo), pero aquí no es posible.Edición final (con suerte ;-)
Breed
, es posible emplear el mismo concepto de subclase / herencia pero conBreed
la entidad principal. En esta configuración, laBreed
tabla tendría las propiedades comunes a todos los tipos deBreed
(al igual que laAnimal
tabla) yRaceID
representaría el tipo deBreed
(igual que en laAnimal
tabla). De allí tendría que tener tablas de subclase comoBreedCat
,BreedDog
y así sucesivamente. Para proyectos más pequeños esto podría considerarse "sobre-ingeniería", pero se menciona como una opción para situaciones que se beneficiarían de él.Para ambos enfoques, a veces ayuda crear Vistas como accesos directos a las entidades completas. Por ejemplo, considere:
CreatedDate
agregaría un campo a laAnimal
tabla. Este campo no es necesario en ninguna de las tablas de subclase (pAnimalCat
. Ej. ), Ya que las filas que se insertan para ambas tablas deben realizarse al mismo tiempo dentro de una transacción.LastModifiedDate
agregaría un campo a laAnimal
tabla y a todas las tablas de subclase. Este campo se actualiza solo si esa tabla en particular se actualiza: si se produce una actualizaciónAnimalCat
pero no enAnimal
una en particularAnimalID
, solo se establecerá elLastModifiedDate
campo enAnimalCat
.fuente
D
, por lo tanto, quería aplicar el método a partir de su respuesta. Dos entidades tienen un atributo comúnE
que no está presente en la tercera entidad. ¿Debo ignorar este hecho y aplicar una solución estándar, o hay alguna manera de optimizar aún más mi diseño?En primer lugar, está haciendo bien para distinguir entre el modelado ER y el modelado relacional. Muchos novatos no lo hacen.
Aquí hay algunas palabras de moda que puede usar para buscar artículos útiles en la web.
Su caso es un caso clásico de clase / subclase o, si lo desea, escriba / subtipo.
La frase que se usa en el modelado ER es "generalización / especialización". Y muchos de los artículos muestran esto bajo algo llamado modelado EER (Enhanced Entity-Relationship). Esto no estaba en la presentación original de Peter Chen del modelado ER. Fue agregado más tarde. Para obtener un resumen bastante bueno de gen / spec en formato pdf, haga clic aquí
A continuación, al convertir un caso de clase / subclase a modelado relacional, diseña tablas. Hay más de un enfoque. Los dos enfoques principales se denominan herencia de tabla única y herencia de tabla de clase. Cada uno tiene ventajas y desventajas. La mejor presentación de estos dos diseños proviene de Martin Fowler. Puedes ver su esquema aquí y aquí .
La gran ventaja de la herencia de una sola tabla es la simplicidad. Todo está almacenado en una tabla. El gran inconveniente son muchos NULLS. Esto puede desperdiciar espacio y tiempo y resultar en una lógica confusa.
La herencia de la tabla de clase requiere uniones, pero son simples y rápidas. Especialmente si usa una técnica llamada clave primaria compartida, en la que el PK en las tablas de subclase es una copia del PK en la tabla de superclase. Puede crear vistas para cada subclase que unan datos de superclase con datos de subclase.
Finalmente, hay una etiqueta en esta área que recopila preguntas como la suya.
Aquí está: subtipos
fuente
Veo el posible diseño como
Mesa
Race
Mesa
Breed
Mesa
Animal
Estas PK anteriores serían columnas de incremento automático. Otras columnas en la
Animal
tabla podrían nombrarse en consecuencia.fuente
Tu método actual no es malo. Sin embargo, si vas a agregar más razas más tarde (aves, peces, etc.), crear una tabla separada para cada una podría ser engorroso. Recomendaría algo como lo siguiente:
Una raza, a mi entender, debería tener una sola raza. Entonces, si almacena la raza en la tabla Animal, podrá determinar la raza uniéndose a la tabla Raza. Obviamente, agregue cualquier otro atributo (nombre, descripción, etc.) a las tablas de Raza y Raza según sea necesario.
fuente