Módulo 17: Restricciones avanzadas
Objetivos del módulo
- Reconocer las restricciones semánticas que un diagrama E/R no puede expresar y aprender a documentarlas de forma rigurosa
- Dominar las cuatro restricciones entre relaciones de la notación de Chen extendida: exclusividad, exclusión, inclusividad e inclusión
- Expresar restricciones sobre una sola relación: reflexivas, de roles distintos y cardinalidades condicionadas
- Detectar y resolver las trampas de conexión: la trampa de abanico (fan trap) y la trampa de sima (chasm trap)
- Analizar ciclos de relaciones para detectar redundancias y decidir cuándo una redundancia es aceptable
- Modelar la dimensión temporal: atributos históricos, relaciones con fecha, entidades de historial y periodos de validez
- Resolver el problema de las relaciones N:M que deben admitir repeticiones
- Tratar correctamente los atributos derivados y la redundancia controlada
- Redactar un catálogo de restricciones de negocio en lenguaje natural y prever cómo se implementará cada una
1. Lo que el diagrama no dice
1.1. El diagrama es necesario, pero no suficiente
Un diagrama E/R expresa muchas cosas: qué entidades hay, qué las identifica, cómo se relacionan y con qué cardinalidades. Pero hay reglas del negocio, a veces muy importantes, que no tienen símbolo en ninguna notación:
- “El precio de venta de un producto nunca puede ser inferior a su precio de coste.”
- “Un empleado no puede ser jefe de sí mismo.”
- “La fecha de devolución de un préstamo es posterior a la fecha de préstamo.”
- “Un socio no puede tener más de tres películas alquiladas a la vez.”
- “Un médico solo puede atender consultas de su especialidad.”
📘 Concepto: Una restricción semántica (o restricción de integridad, integrity constraint) es una condición que deben cumplir los datos para representar correctamente la realidad. Las que el modelo puede expresar con su notación se llaman restricciones inherentes o estructurales (identificadores, cardinalidades, cobertura de jerarquías); las demás son restricciones explícitas y hay que documentarlas aparte.
Si no documentas las restricciones explícitas, se pierden: el diseñador lógico no las verá, el programador no las implementará y la base de datos aceptará datos incorrectos. Un esquema conceptual completo es siempre diagrama + diccionario de datos + lista de restricciones.
1.2. Clasificación de las restricciones
| Tipo | Qué restringe | Ejemplo | Dónde acabará |
|---|---|---|---|
| De dominio | Los valores posibles de un atributo | “La nota está entre 0 y 10” | CHECK de columna, tipo de dato, dominio SQL |
| De obligatoriedad / unicidad | Si un atributo es obligatorio o único | “El email es único” | NOT NULL, UNIQUE |
| Entre atributos de la misma ocurrencia | Combinación de valores de una fila | “fecha_fin ≥ fecha_inicio” | CHECK de tabla |
| Entre ocurrencias de la misma entidad | Combinación de varias filas | “No hay dos reservas solapadas de la misma habitación” | Trigger o aplicación |
| De cardinalidad condicionada | Máximos o mínimos que dependen de algo | “Un alumno de primer curso se matricula como máximo en 6 asignaturas” | Trigger o aplicación |
| Entre relaciones | Participación en unas relaciones según otras | “Un vehículo pertenece a una persona o a una empresa” | CHECK, clave ajena compuesta, trigger |
| Temporales / de transición | Cambios de estado permitidos | “Un pedido entregado no puede volver a pendiente” | Trigger o aplicación |
| Derivación | Cómo se calcula un dato | “importe = cantidad × precio × (1 − descuento/100)” | Columna virtual, vista, trigger |
💡 Consejo: La última columna anticipa el diseño físico. Cuando transformes el modelo a SQL verás que las restricciones de una sola fila se implementan con
CHECK, y las que implican varias filas o varias tablas suelen necesitar triggers, que se estudian en el Curso de Oracle PL/SQL, o lógica en la aplicación.
1.3. Cómo anotarlas
Hay tres formas complementarias de dejar constancia de una restricción:
- En el diagrama, si la notación tiene símbolo (cardinalidades, cobertura, las restricciones entre relaciones de la sección 2).
- Como nota numerada junto al diagrama: un recuadro con la etiqueta
R1,R2… unido con línea discontinua al elemento afectado. - En el catálogo de restricciones del diccionario de datos (módulo 14), con su enunciado completo, los elementos implicados y la forma de implementación prevista.
En este curso dibujamos las notas como un rectángulo unido con línea discontinua:
flowchart LR
classDef nota fill:#fff8dc,stroke:#999,stroke-dasharray: 3 3
EMPLEADO[EMPLEADO] ---|"(0,1) jefe"| dirige{"dirige<br/>1:N"}
dirige ---|"(0,n) subordinado"| EMPLEADO
EMPLEADO --- e_id([<u>num_empleado</u>])
EMPLEADO --- e_sal([salario])
R1["R1: un empleado no puede ser jefe de sí mismo"]:::nota
R2["R2: el salario de un empleado no supera el de su jefe"]:::nota
R1 -.- dirige
R2 -.- e_sal
Cada nota debe ser breve, precisa y verificable: alguien debe poder decir, mirando los datos, si la restricción se cumple o no. “Los salarios deben ser razonables” no es una restricción; “el salario es mayor que 0 y no supera 10 000 €” sí lo es.
2. Restricciones entre relaciones
Cuando una misma entidad participa en varias relaciones, a menudo existen reglas que ligan su participación en unas con su participación en otras. La notación de Chen extendida, tal como la presentan de Miguel y Piattini, define cuatro restricciones de este tipo.
| Restricción | Idea en una frase | Nivel |
|---|---|---|
| Exclusividad | Cada ocurrencia participa en una u otra relación, no en las dos | Ocurrencia de la entidad |
| Exclusión | Un mismo par de ocurrencias no puede estar en las dos relaciones | Par de ocurrencias |
| Inclusividad | Para participar en una relación, la ocurrencia tiene que haber participado (n veces) en la otra | Ocurrencia de la entidad |
| Inclusión | Para que un par esté en una relación, el mismo par tiene que estar en la otra | Par de ocurrencias |
Fíjate en la simetría: exclusividad e inclusividad hablan de una ocurrencia de la entidad común; exclusión e inclusión hablan de un par concreto de ocurrencias. Es lo que más cuesta distinguir al principio, así que lo veremos con ocurrencias.
2.1. Notación del curso
Mermaid no dispone del “arco” que se dibuja en papel, así que en este curso las restricciones entre relaciones se representan con una línea discontinua entre los rombos afectados, etiquetada con el nombre de la restricción:
| Restricción | En papel (de Miguel y Piattini) | En Mermaid (este curso) |
|---|---|---|
| Exclusividad | Arco que corta las líneas de las relaciones junto a la entidad común | r1 -.-\|"exclusividad"\| r2 |
| Exclusión | Línea discontinua entre los rombos | r1 -.-\|"exclusión"\| r2 |
| Inclusividad | Flecha discontinua de la relación condicionada a la condicionante, con (mín, máx) | r2 -.->\|"inclusividad (mín,máx)"\| r1 |
| Inclusión | Flecha discontinua de la relación incluida a la que la incluye | r2 -.->\|"inclusión"\| r1 |
⚠️ Importante: La flecha de inclusividad e inclusión va desde la relación que impone la condición (la “posterior” o subordinada) hacia la relación que debe cumplirse antes. Léela como “R2 exige R1”.
2.2. Exclusividad
📘 Concepto: Dos o más relaciones R1, R2, …, Rn en las que participa una entidad E son exclusivas respecto a E si cada ocurrencia de E participa como mucho en una de ellas. Si además la participación es obligatoria (cada ocurrencia participa exactamente en una), se habla de exclusividad total.
💻 Ejemplo: En un registro de vehículos, cada
VEHICULOpertenece a unaPERSONAo a unaEMPRESA, nunca a las dos a la vez, y siempre a alguna de ellas.
flowchart LR
PERSONA[PERSONA] ---|"(0,1)"| posee_p{"posee_p<br/>1:N"}
posee_p ---|"(0,n)"| VEHICULO[VEHICULO]
EMPRESA[EMPRESA] ---|"(0,1)"| posee_e{"posee_e<br/>1:N"}
posee_e ---|"(0,n)"| VEHICULO
posee_p -.-|"exclusividad"| posee_e
Fíjate en las cardinalidades junto a PERSONA y EMPRESA: son (0,1), porque un vehículo concreto puede no tener persona propietaria (si es de una empresa), y viceversa. La obligatoriedad (“todo vehículo tiene propietario”) no puede expresarse con las mínimas de cada relación por separado: es la propia restricción de exclusividad total la que la recoge. Anótalo así: “exclusividad total: todo vehículo participa en exactamente una de las relaciones posee_p y posee_e”.
Ocurrencias válidas y no válidas:
| Vehículo | Persona propietaria | Empresa propietaria | ¿Válido? |
|---|---|---|---|
| 1234-ABC | 11111111H | — | Sí |
| 5678-DEF | — | B12345678 | Sí |
| 9012-GHI | 22222222J | B12345678 | No: participa en las dos |
| 3456-JKL | — | — | No si la exclusividad es total; sí si es parcial |
Exclusividad, categoría y jerarquía
Este mismo problema puede modelarse de tres maneras, todas correctas, y conviene saber elegir:
| Opción | Cuándo es preferible |
|---|---|
| Exclusividad entre relaciones (este apartado) | Hay una sola relación afectada (la propiedad) y las entidades son independientes |
Categoría PROPIETARIO ⊆ PERSONA ∪ EMPRESA (módulo 11) | El “propietario” participa en varias relaciones (posee, paga impuestos, recibe multas…) o tiene atributos propios |
Jerarquía TITULAR → PERSONA, EMPRESA (módulo 11) | Personas y empresas comparten identificador y atributos, y no tienen vida fuera del sistema |
Exclusividad entre más de dos relaciones
La exclusividad puede afectar a tres o más relaciones. Por ejemplo, un PAGO se realiza con una de estas formas: tarjeta, transferencia o bizum, cada una con su entidad (TARJETA, CUENTA_BANCARIA, TELEFONO_MOVIL). Dibuja la línea discontinua entre cada par de rombos o, para no recargar el diagrama, una nota “exclusividad total entre r1, r2 y r3”.
💡 Consejo: Al pasar a tablas, la exclusividad entre relaciones 1:N se implementa muy bien con columnas de clave ajena opcionales y un
CHECKde fila. Por ejemplo, para el vehículo:CHECK ((dni_persona IS NOT NULL AND cif_empresa IS NULL) OR (dni_persona IS NULL AND cif_empresa IS NOT NULL)). Lo verás en el bloque de diseño lógico.
2.3. Exclusión
📘 Concepto: Dos relaciones R1 y R2 entre las mismas entidades A y B son excluyentes si un mismo par (a, b) no puede aparecer en las dos: (a, b) ∈ R1 ⟹ (a, b) ∉ R2. Una ocurrencia de A sí puede participar en ambas relaciones, siempre que lo haga con ocurrencias distintas de B.
💻 Ejemplo: En un centro de formación, los profesores imparten cursos y también pueden recibir cursos (como alumnos). Un profesor no puede impartir y recibir el mismo curso, pero sí impartir el curso de SQL y recibir el de Python.
flowchart LR
PROFESOR[PROFESOR] ---|"(1,n)"| imparte{"imparte<br/>N:M"}
imparte ---|"(0,n)"| CURSO[CURSO]
PROFESOR ---|"(0,n)"| recibe{"recibe<br/>N:M"}
recibe ---|"(0,n)"| CURSO
imparte -.-|"exclusión"| recibe
Ocurrencias:
| Relación | Profesor | Curso |
|---|---|---|
| imparte | Pérez | SQL |
| imparte | López | Python |
| recibe | Pérez | Python |
| recibe | López | SQL |
| recibe | Pérez | SQL ← violación: Pérez ya imparte SQL |
Diferencia con la exclusividad: si fuera exclusividad, Pérez no podría recibir ningún curso por el hecho de impartir alguno. Con exclusión, solo le está prohibido el par concreto (Pérez, SQL).
⚠️ Importante: La exclusión solo tiene sentido entre relaciones que unen las mismas entidades (o entidades de la misma jerarquía). La exclusividad, en cambio, suele darse entre relaciones que unen una entidad común con entidades distintas.
Otro ejemplo frecuente: en una liga, un EQUIPO juega un PARTIDO como local o como visitante; un mismo equipo no puede ser local y visitante del mismo partido. Es una exclusión entre las relaciones local y visitante (aunque aquí, además, cada partido tiene exactamente un local y un visitante).
2.4. Inclusividad
📘 Concepto: Una relación R2 es inclusiva respecto a otra R1 (sobre una entidad común E) si toda ocurrencia de E que participa en R2 tiene que haber participado antes (o a la vez) en R1. Se puede precisar cuántas veces con una pareja (mín, máx): para participar en R2, la ocurrencia de E debe haber participado en R1 entre mín y máx veces.
💻 Ejemplo: Para que un
EMPLEADOpueda impartir cursos de formación interna, tiene que haber recibido al menos 2 cursos (cualesquiera).
flowchart LR
EMPLEADO[EMPLEADO] ---|"(0,n)"| imparte{"imparte<br/>N:M"}
imparte ---|"(0,n)"| CURSO[CURSO]
EMPLEADO ---|"(0,n)"| recibe{"recibe<br/>N:M"}
recibe ---|"(0,n)"| CURSO
imparte -.->|"inclusividad (2,n)"| recibe
Lectura: “un empleado que participa en imparte debe participar al menos 2 veces en recibe”. No importa qué cursos recibió: puede impartir el de Excel habiendo recibido los de liderazgo y prevención de riesgos.
Otros ejemplos de inclusividad:
- Para dirigir un proyecto, un empleado debe haber participado antes en al menos un proyecto (cualquiera).
- Para divorciarse, una persona tiene que haber contraído matrimonio al menos una vez (ejemplo clásico de de Miguel y Piattini).
- Para arbitrar en primera división, un árbitro debe haber arbitrado al menos 50 partidos en segunda.
2.5. Inclusión
📘 Concepto: Una relación R2 entre A y B está incluida en otra R1 entre las mismas entidades si todo par (a, b) que aparece en R2 aparece también en R1: R2 ⊆ R1.
💻 Ejemplo: Un alumno solo puede examinarse de una asignatura en la que está matriculado.
flowchart LR
ALUMNO[ALUMNO] ---|"(0,n)"| matricula{"matricula<br/>N:M"}
matricula ---|"(1,n)"| ASIGNATURA[ASIGNATURA]
ALUMNO ---|"(0,n)"| examina{"se_examina<br/>N:M"}
examina ---|"(0,n)"| ASIGNATURA
examina -.->|"inclusión"| matricula
Ocurrencias:
| Relación | Alumno | Asignatura | ¿Válido? |
|---|---|---|---|
| matricula | Ana | Bases de Datos | Sí |
| matricula | Ana | Programación | Sí |
| se_examina | Ana | Bases de Datos | Sí: el par está en matricula |
| se_examina | Ana | Redes | No: Ana no está matriculada en Redes |
Diferencia con la inclusividad: con inclusividad, bastaría con que Ana estuviera matriculada en alguna asignatura para examinarse de cualquiera. Con inclusión, tiene que estar matriculada en esa misma asignatura.
💡 Consejo: La inclusión tiene una implementación muy elegante en el modelo relacional: la tabla de
se_examinatiene una clave ajena compuesta (alumno, asignatura) que referencia la clave primaria de la tabla dematricula. Así el SGBD garantiza la restricción sin una sola línea de código. Es una de las pocas restricciones entre relaciones que no necesita triggers.
⚠️ Importante: Cuando hay inclusión, piensa si la relación incluida no debería ser, en realidad, un atributo o una relación de la incluyente. En el ejemplo, ¿no son las convocatorias de examen algo que ocurre dentro de la matrícula? Si es así, una solución mejor es una entidad débil
CONVOCATORIAdependiente de la matrícula (o una agregación dematricula). La inclusión desaparece porque queda garantizada por la estructura.
2.6. Comparación de las cuatro restricciones
| Exclusividad | Exclusión | Inclusividad | Inclusión | |
|---|---|---|---|---|
| Afecta a | Una ocurrencia de E | Un par (a, b) | Una ocurrencia de E | Un par (a, b) |
| Entidades de las relaciones | Normalmente distintas | Las mismas | Pueden ser distintas | Las mismas |
| Condición formal | e participa en a lo sumo una Ri | (a,b) ∈ R1 ⟹ (a,b) ∉ R2 | e ∈ π_E(R2) ⟹ e participa en R1 entre mín y máx veces | R2 ⊆ R1 |
| Pregunta típica | “¿Una cosa u otra?” | “¿Lo mismo no puede estar en las dos?” | “¿Para hacer esto, hay que haber hecho antes aquello?” | “¿Esto concreto exige aquello mismo?” |
| Ejemplo | Vehículo de persona o de empresa | No impartir y recibir el mismo curso | Impartir exige haber recibido 2 cursos | Examinarse exige estar matriculado en esa asignatura |
| Implementación habitual | CHECK sobre claves ajenas opcionales | Trigger o aplicación | Trigger o aplicación | Clave ajena compuesta |
3. Restricciones sobre una sola relación
3.1. Relaciones reflexivas
En una relación reflexiva (o recursiva), una entidad se relaciona consigo misma desempeñando dos papeles distintos (módulo 06). Casi siempre arrastran restricciones que el diagrama no recoge:
| Restricción | Significado | Ejemplo |
|---|---|---|
| Irreflexividad | Ninguna ocurrencia se relaciona consigo misma | Un empleado no es jefe de sí mismo |
| Aciclicidad | No hay ciclos: si A → B → C, entonces C no puede llegar a A | Una categoría no puede ser “abuela” de sí misma |
| Asimetría | Si (a, b) está, (b, a) no puede estar | Si A es jefe de B, B no es jefe de A |
| Simetría | Si (a, b) está, (b, a) también se considera | La amistad en una red social |
| Profundidad máxima | Número máximo de niveles | Como mucho 4 niveles de categorías |
flowchart LR
classDef nota fill:#fff8dc,stroke:#999,stroke-dasharray: 3 3
CATEGORIA[CATEGORIA] ---|"(0,1) padre"| contiene{"contiene<br/>1:N"}
contiene ---|"(0,n) hija"| CATEGORIA
CATEGORIA --- c_id([<u>cod_categoria</u>])
CATEGORIA --- c_nom([nombre])
R3["R3: la jerarquía de categorías es acíclica y tiene como máximo 4 niveles"]:::nota
R3 -.- contiene
⚠️ Importante: La simetría merece una decisión explícita en el diccionario. Si “Ana es amiga de Luis” implica “Luis es amigo de Ana”, ¿guardas el par una vez o dos? Si lo guardas una vez, documenta una regla de orden (por ejemplo, “el primer usuario es el de menor identificador”) para evitar que el mismo hecho aparezca como (Ana, Luis) y (Luis, Ana).
3.2. Varias relaciones entre las mismas entidades con papeles distintos
Cuando dos entidades están unidas por varias relaciones (o una entidad está unida dos veces a otra con papeles distintos), suelen aparecer restricciones de distinción de papeles.
💻 Ejemplo: Un
PARTIDOtiene un equipo local y un equipo visitante.
flowchart LR
classDef nota fill:#fff8dc,stroke:#999,stroke-dasharray: 3 3
EQUIPO[EQUIPO] ---|"(1,1) local"| local{"juega_local<br/>1:N"}
local ---|"(0,n)"| PARTIDO[PARTIDO]
EQUIPO ---|"(1,1) visitante"| visit{"juega_visitante<br/>1:N"}
visit ---|"(0,n)"| PARTIDO
local -.-|"exclusión"| visit
R4["R4: en una misma jornada un equipo juega como mucho un partido"]:::nota
R4 -.- PARTIDO
- La exclusión entre
juega_localyjuega_visitantegarantiza que el local y el visitante de un partido son equipos distintos. - La nota R4 es una restricción entre ocurrencias de
PARTIDOque ninguna notación puede expresar.
3.3. Cardinalidades condicionadas
Las cardinalidades del diagrama son fijas. Cuando el máximo o el mínimo depende de otro dato, hay que anotarlo:
- “Un alumno de primer curso se matricula de 1 a 6 asignaturas; los de cursos superiores, de 1 a 10.”
- “Una habitación doble aloja como máximo 2 huéspedes por reserva; una suite, 4.”
- “Un socio premium puede tener 5 películas alquiladas a la vez; uno básico, 2.”
En el diagrama se dibuja la cardinalidad más amplia (la que admite todos los casos: (1,10), (1,4), (0,5)…) y la condición se escribe como restricción. Si la diferencia está ligada a un subtipo con atributos propios, a veces conviene crear una jerarquía y unir la relación con cardinalidades distintas a cada subtipo (módulo 11).
💡 Consejo: Observa además que “tener 5 películas alquiladas a la vez” no es una cardinalidad de la relación
alquilaen sentido estricto, porque un socio puede alquilar cientos de películas a lo largo del tiempo. Es una restricción sobre las ocurrencias vigentes (sin devolver). Las restricciones “a la vez” casi siempre son temporales: lo verás en la sección 7.
3.4. Restricciones que afectan a caminos
Algunas reglas exigen que dos caminos distintos del diagrama lleven al mismo sitio:
💻 Ejemplo: “Un médico solo puede atender consultas de pacientes asignados a su mismo centro de salud.” Hay dos caminos de
CONSULTAaCENTRO: CONSULTA → MEDICO → CENTRO y CONSULTA → PACIENTE → CENTRO. La restricción exige que ambos caminos den el mismo centro.
Estas restricciones de “caminos coincidentes” aparecen en los ciclos del diagrama y las estudiamos con más detalle en la sección 6.
4. Relaciones de grado superior
Muchas de las restricciones de este módulo aparecen también en las relaciones ternarias y n-arias, en las que un hecho involucra simultáneamente a tres o más entidades (un proveedor suministra una pieza a un proyecto; un profesor imparte una asignatura a un grupo en un aula). En ellas, el cálculo de cardinalidades se hace fijando pares de ocurrencias, y su sustitución por varias relaciones binarias puede perder información.
💡 Consejo: Todo lo relativo a las relaciones ternarias y n-arias (cuándo son necesarias, cómo calcular sus cardinalidades, cuándo pueden descomponerse en binarias y cómo transformarlas en entidad) se estudia en el módulo de relaciones ternarias. En este módulo solo las usaremos puntualmente, en el apartado de las relaciones con repetición (sección 8).
5. Trampas de conexión
Las trampas de conexión (connection traps), descritas por Codd y popularizadas por Connolly y Begg, son defectos de diseño en los que el diagrama parece permitir responder a una pregunta, pero en realidad la información necesaria no está o está mezclada. Son muy traicioneras porque el diagrama es sintácticamente correcto y las cardinalidades pueden ser exactas: el problema está en dónde se ha colocado cada relación.
5.1. Trampa de abanico (fan trap)
📘 Concepto: Hay una trampa de abanico cuando de una misma entidad salen dos o más relaciones 1:N (en “abanico”) y se pretende deducir la relación entre las entidades del otro extremo. El camino entre ellas es ambiguo.
💻 Ejemplo: Una empresa se organiza en divisiones. Cada división opera varias sucursales y tiene contratados varios empleados. Se ha modelado así:
flowchart LR
SUCURSAL[SUCURSAL] ---|"(1,n)"| opera{"opera<br/>1:N"}
opera ---|"(1,1)"| DIVISION[DIVISION]
DIVISION ---|"(1,1)"| tiene{"tiene<br/>1:N"}
tiene ---|"(1,n)"| EMPLEADO[EMPLEADO]
Lectura: cada sucursal pertenece a una división; cada empleado pertenece a una división. Todo correcto… hasta que alguien pregunta: “¿en qué sucursal trabaja el empleado Ruiz?”
Ocurrencias:
| opera (sucursal → división) | tiene (empleado → división) |
|---|---|
| Sucursal Madrid → División Norte | Ruiz → División Norte |
| Sucursal Burgos → División Norte | Gómez → División Norte |
| Sucursal Sevilla → División Sur | Díaz → División Sur |
Desde Ruiz llegamos a la División Norte, y desde ella a dos sucursales: Madrid y Burgos. Es imposible saber en cuál trabaja Ruiz. La información no existe en el modelo.
Solución: reestructurar para que el camino sea el correcto. Si cada empleado trabaja en una sucursal y cada sucursal pertenece a una división, la relación debe ir de la sucursal al empleado:
flowchart LR
DIVISION[DIVISION] ---|"(1,1)"| opera{"opera<br/>1:N"}
opera ---|"(1,n)"| SUCURSAL[SUCURSAL]
SUCURSAL ---|"(1,1)"| trabaja{"trabaja<br/>1:N"}
trabaja ---|"(1,n)"| EMPLEADO[EMPLEADO]
Ahora desde Ruiz llegamos a una única sucursal (Madrid), y desde ella a una única división: la pregunta “¿en qué división trabaja Ruiz?” sigue teniendo respuesta, por composición de relaciones.
⚠️ Importante: Si hay empleados que dependen directamente de la división sin sucursal (por ejemplo, el personal de la sede de la división), la solución anterior no basta: habría que mantener también una relación DIVISION–EMPLEADO y una exclusividad entre
trabajay esa relación, o hacertrabajaopcional y anotar una restricción. La reestructuración siempre debe partir de la realidad, no de una receta.
Cómo detectarla: busca entidades de las que salgan dos o más relaciones con cardinalidad máxima n hacia el otro lado y pregúntate: “¿necesito saber cómo se relacionan entre sí las entidades del otro extremo?”. Si la respuesta es sí, tienes un abanico.
5.2. Trampa de sima o de abismo (chasm trap)
📘 Concepto: Hay una trampa de sima (o de abismo) cuando el modelo sugiere que existe un camino entre dos entidades, pero ese camino pasa por una relación de participación opcional (mínima 0), de modo que para algunas ocurrencias el camino se interrumpe y la información se pierde.
💻 Ejemplo: Una inmobiliaria tiene oficinas; cada oficina tiene empleados, y algunos empleados supervisan inmuebles en alquiler. Cada inmueble lo ofrece una oficina, pero puede no tener todavía un empleado supervisor asignado. Se ha modelado así:
flowchart LR
OFICINA[OFICINA] ---|"(1,1)"| tiene{"tiene<br/>1:N"}
tiene ---|"(1,n)"| EMPLEADO[EMPLEADO]
EMPLEADO ---|"(0,1)"| supervisa{"supervisa<br/>1:N"}
supervisa ---|"(0,n)"| INMUEBLE[INMUEBLE]
Lectura: cada empleado está en una oficina; cada empleado supervisa de 0 a n inmuebles; cada inmueble tiene 0 o 1 supervisor. Pregunta: “¿qué oficina ofrece el inmueble de la calle Mayor, 5?”
Ocurrencias:
| Inmueble | Supervisor | Oficina del supervisor |
|---|---|---|
| C/ Mayor, 3 | Pérez | Oficina Centro |
| C/ Mayor, 5 | — | ¿? |
| Av. Libertad, 12 | López | Oficina Norte |
Para los inmuebles sin supervisor, el camino INMUEBLE → EMPLEADO → OFICINA se rompe: hay una “sima” en medio. El enunciado dice que todo inmueble lo ofrece una oficina, pero el modelo no puede decirnos cuál.
Solución: añadir la relación que falta directamente entre las entidades:
flowchart LR
OFICINA[OFICINA] ---|"(1,1)"| tiene{"tiene<br/>1:N"}
tiene ---|"(1,n)"| EMPLEADO[EMPLEADO]
EMPLEADO ---|"(0,1)"| supervisa{"supervisa<br/>1:N"}
supervisa ---|"(0,n)"| INMUEBLE[INMUEBLE]
OFICINA ---|"(1,1)"| ofrece{"ofrece<br/>1:N"}
ofrece ---|"(0,n)"| INMUEBLE
Ahora el modelo tiene un ciclo (OFICINA–EMPLEADO–INMUEBLE–OFICINA) y aparece una restricción nueva que hay que anotar: “si un inmueble tiene supervisor, el supervisor pertenece a la misma oficina que ofrece el inmueble” (si esa es la regla del negocio). Es una restricción de caminos coincidentes (sección 3.4).
Cómo detectarla: busca caminos que usas para responder preguntas importantes y comprueba si alguna relación del camino tiene mínima 0 en el sentido en que lo recorres. Si es así, pregúntate: “¿qué pasa con las ocurrencias que no participan?”.
5.3. Comparación
| Trampa de abanico | Trampa de sima | |
|---|---|---|
| Síntoma | El camino existe pero es ambiguo (lleva a varias ocurrencias) | El camino se interrumpe para algunas ocurrencias |
| Causa | Dos relaciones 1:N que salen de la misma entidad | Una relación con participación opcional en medio del camino |
| Se detecta con la pregunta | “¿A cuál de todas?” | “¿Y los que no tienen…?” |
| Solución | Reestructurar las relaciones para que el camino sea el correcto | Añadir la relación directa que falta |
| Efecto secundario | Desaparece una relación y se crea otra | Aparece un ciclo, normalmente con una restricción de consistencia |
💡 Consejo: Las trampas se descubren haciendo preguntas al diagrama. Al terminar un diseño, toma la lista de consultas que el usuario necesita (“listado de empleados por sucursal”, “inmuebles de cada oficina”) e intenta responder cada una recorriendo el diagrama con el dedo. Si alguna pregunta tiene varias respuestas o ninguna, has encontrado una trampa.
6. Redundancia de relaciones y ciclos
6.1. Ciclos en el diagrama
📘 Concepto: Un ciclo es un camino cerrado de relaciones que empieza y termina en la misma entidad. Una relación de un ciclo es redundante si su contenido puede deducirse por composición de las demás relaciones del ciclo, para todas las ocurrencias y en todo momento.
Los ciclos no son malos en sí: muchos son necesarios. Lo que hay que hacer con cada ciclo es analizarlo para decidir entre tres posibilidades:
- Una relación es redundante → se elimina (o se mantiene como redundancia controlada y documentada).
- Ninguna es redundante, pero los caminos deben coincidir → se mantiene el ciclo y se anota una restricción.
- Ninguna es redundante y los caminos son independientes → se mantiene el ciclo sin más.
6.2. Ejemplo de relación redundante
💻 Ejemplo: En un instituto, cada alumno pertenece a un grupo (1ºA, 1ºB…), cada grupo pertenece a un curso (1º de ESO, 2º de ESO…), y además alguien ha dibujado que el alumno “está en” un curso.
flowchart LR
ALUMNO[ALUMNO] ---|"(0,n)"| pertenece{"pertenece<br/>1:N"}
pertenece ---|"(1,1)"| GRUPO[GRUPO]
GRUPO ---|"(1,n)"| es_de{"es_de<br/>1:N"}
es_de ---|"(1,1)"| CURSO[CURSO]
ALUMNO ---|"(0,n)"| esta_en{"esta_en<br/>1:N"}
esta_en ---|"(1,1)"| CURSO
Si cada alumno está en exactamente un grupo y cada grupo es de exactamente un curso, el curso del alumno se deduce siempre: alumno → grupo → curso. La relación esta_en es redundante:
- Ocupa espacio sin aportar información.
- Puede llevar a inconsistencias: que Ana esté en el grupo 1ºA (de 1º de ESO) y
esta_endiga 2º de ESO.
Solución: eliminar esta_en.
6.3. Ejemplo de ciclo no redundante
💻 Ejemplo: En una universidad, cada profesor está adscrito a un departamento, cada asignatura pertenece a un departamento y cada profesor imparte asignaturas.
flowchart LR
PROFESOR[PROFESOR] ---|"(0,n)"| adscrito{"adscrito<br/>1:N"}
adscrito ---|"(1,1)"| DEPARTAMENTO[DEPARTAMENTO]
ASIGNATURA[ASIGNATURA] ---|"(1,n)"| pertenece{"pertenece<br/>1:N"}
pertenece ---|"(1,1)"| DEPARTAMENTO
PROFESOR ---|"(1,n)"| imparte{"imparte<br/>N:M"}
imparte ---|"(0,n)"| ASIGNATURA
¿Es redundante alguna relación? Analicemos:
- ¿Se deduce
impartede las otras dos? No: saber que el profesor y la asignatura son del mismo departamento no dice qué asignaturas imparte cada profesor. - ¿Se deduce
adscrito? No: un profesor puede impartir asignaturas de varios departamentos (por ejemplo, un profesor de Matemáticas que da Estadística en el grado de Economía), y entonces no sabríamos a cuál está adscrito. - ¿Se deduce
pertenece? No, por la misma razón.
Ninguna es redundante. Pero, si el negocio dijera “un profesor solo puede impartir asignaturas de su departamento”, el ciclo tendría una restricción de caminos coincidentes que habría que anotar.
6.4. Procedimiento para analizar un ciclo
Para cada ciclo del diagrama, y para cada relación R del ciclo:
- Elimina mentalmente R y recorre el resto del ciclo entre las dos entidades que R unía.
- Si el camino alternativo devuelve exactamente las mismas parejas que R, para todas las ocurrencias, R es redundante. Para ello normalmente hace falta que las relaciones del camino alternativo tengan máximo 1 en el sentido del recorrido (si alguna tiene máximo n, el camino devuelve varias ocurrencias y no puede sustituir a R).
- Si el camino devuelve un superconjunto de R (más parejas), R no es redundante, pero hay una restricción de inclusión implícita: R ⊆ composición del camino. Anótala si es una regla del negocio.
- Si el camino puede devolver parejas que no están en R y R puede tener parejas que no devuelve el camino, el ciclo es independiente.
- Comprueba también la dimensión temporal: dos relaciones pueden coincidir hoy y dejar de hacerlo mañana (ver 6.5).
6.5. Una redundancia aparente: el tiempo
💻 Ejemplo: En una tienda, cada
PEDIDOlo hace unCLIENTE, y cada cliente tiene asignado unCOMERCIAL. Además, cada pedido registra el comercial que lo gestionó. ¿Es redundante pedido → comercial, ya que se puede obtener por pedido → cliente → comercial?
No lo es, por dos motivos:
- El comercial asignado a un cliente cambia con el tiempo. Si en 2026 Ana atendía al cliente y en 2027 pasa a atenderlo Luis, los pedidos de 2026 deben seguir figurando como gestionados por Ana.
- Puede que un pedido lo gestione otro comercial (por vacaciones del asignado).
Es exactamente lo que ocurre en el esquema EMPRESA de este curso: CLIENTES tiene comercial_id y PEDIDOS tiene empleado_id, y no son redundantes (lo verás en el caso EMPRESA del módulo 15).
6.6. Cuándo es aceptable una redundancia
A veces se mantiene una relación o un atributo redundante a propósito. Se habla entonces de redundancia controlada, y es aceptable si se cumplen todas estas condiciones:
| Condición | Explicación |
|---|---|
| Está justificada | Por rendimiento (evitar recorrer un camino largo en consultas muy frecuentes) o por claridad para el usuario |
| Está documentada | En el diccionario figura qué elemento es redundante y de qué se deduce |
| Hay un mecanismo de consistencia | Una restricción que garantice que el dato redundante coincide con el deducido (trigger, proceso de la aplicación, vista materializada) |
| Se ha valorado el coste | Cada modificación del dato original obliga a actualizar el redundante |
⚠️ Importante: En el modelo conceptual, la regla general es no incluir redundancias: el modelo conceptual describe la realidad, no el rendimiento. Las redundancias controladas por rendimiento se introducen más tarde, en el diseño lógico o físico (desnormalización, módulo 20). Si las dibujas en el modelo conceptual, márcalas y justifícalas.
7. La dimensión temporal
7.1. Instantánea o historia
Casi todas las bases de datos tienen que decidir, para cada dato que cambia, si les interesa solo su valor actual (una instantánea) o todos los valores que ha tenido (su historia). El modelo E/R básico no tiene ningún mecanismo especial para el tiempo: todo lo que tenga que ver con la historia hay que modelarlo explícitamente.
| Necesidad | Ejemplo | Modelado |
|---|---|---|
| Solo valor actual | Teléfono de un cliente | Atributo simple |
| Valor en un momento concreto, congelado | Precio cobrado en una venta | Atributo de la relación o de la entidad débil (línea de pedido) |
| Historia completa de un atributo | Evolución del salario de un empleado | Entidad de historial débil |
| Historia de una relación | Departamentos por los que ha pasado un empleado | Relación con fechas convertida en entidad |
| Estado actual + historia de estados | Estados de un pedido | Atributo estado + entidad CAMBIO_ESTADO |
💡 Consejo: Pregunta siempre en las entrevistas: “¿y si este dato cambia, os interesa saber el valor anterior?”. Es una de las preguntas que más modifican un diseño, y casi nunca la responde el enunciado de forma explícita.
7.2. Atributos históricos
💻 Ejemplo: Interesa conocer la evolución del salario de cada empleado: cuánto cobraba en cada periodo.
Un atributo multivaluado compuesto (salario_historico con importe y fecha_desde) sería válido en el modelo conceptual, pero es más claro y más fácil de transformar modelarlo como entidad débil:
flowchart LR
classDef debil stroke-width:4px
EMPLEADO[EMPLEADO] --- e_id([<u>num_empleado</u>])
EMPLEADO --- e_nom([nombre])
EMPLEADO --- e_sal([salario_actual])
EMPLEADO ---|"(1,1)"| tiene{"tiene<br/>ID"}:::debil
tiene ---|"(0,n)"| HSAL[HISTORICO_SALARIO]:::debil
HSAL --- h_ini(["<u>fecha_desde</u> parcial"])
HSAL --- h_fin(["fecha_hasta (0,1)"])
HSAL --- h_imp([importe])
HISTORICO_SALARIOse identifica por el empleado +fecha_desde(identificador parcial).fecha_hastaes opcional: el periodo vigente no tiene fin.salario_actualenEMPLEADOes redundante con el registro vigente del historial. Puedes eliminarlo (y obtener el salario actual buscando el periodo sinfecha_hasta) o mantenerlo como redundancia controlada documentada.
Restricciones que hay que anotar:
- R1: fecha_hasta ≥ fecha_desde.
- R2: los periodos de un mismo empleado no se solapan.
- R3: como mucho un periodo vigente (sin
fecha_hasta) por empleado. - R4 (opcional): los periodos son contiguos, sin huecos (cada fecha_desde es el día siguiente al fecha_hasta anterior).
⚠️ Importante: Las restricciones de no solapamiento de periodos (R2) son de las más frecuentes en las bases de datos reales, y no pueden implementarse con un
CHECKporque comparan varias filas. Requieren triggers o lógica de aplicación.
7.3. De relación actual a relación histórica
Este es uno de los cambios más importantes que introduce el tiempo: las cardinalidades cambian.
💻 Ejemplo: “Cada empleado trabaja en un departamento.” Si solo interesa el departamento actual, la relación es 1:N:
flowchart LR
EMPLEADO[EMPLEADO] ---|"(1,n)"| trabaja{"trabaja<br/>1:N"}
trabaja ---|"(1,1)"| DEPARTAMENTO[DEPARTAMENTO]
Si interesa la historia (“en qué departamentos ha trabajado y cuándo”), un empleado ha podido estar en muchos departamentos a lo largo del tiempo, y la relación pasa a ser N:M con atributos de periodo:
flowchart LR
EMPLEADO[EMPLEADO] ---|"(0,n)"| trabajo{"ha_trabajado<br/>N:M"}
trabajo ---|"(1,n)"| DEPARTAMENTO[DEPARTAMENTO]
trabajo --- t_ini([fecha_inicio])
trabajo --- t_fin(["fecha_fin (0,1)"])
Pero cuidado: con esta relación N:M, cada par (empleado, departamento) solo puede aparecer una vez. Si Ana estuvo en Ventas de 2018 a 2020, pasó a Marketing y volvió a Ventas en 2023, no podemos registrar las dos estancias en Ventas. Es el problema de las relaciones con repetición, que resolvemos en la sección 8 convirtiendo la relación en entidad:
flowchart LR
classDef debil stroke-width:4px
EMPLEADO[EMPLEADO] ---|"(1,1)"| tiene{"tiene<br/>ID"}:::debil
tiene ---|"(1,n)"| ESTANCIA[ESTANCIA]:::debil
ESTANCIA --- es_ini(["<u>fecha_inicio</u> parcial"])
ESTANCIA --- es_fin(["fecha_fin (0,1)"])
ESTANCIA ---|"(0,n)"| en{"en<br/>1:N"}
en ---|"(1,1)"| DEPARTAMENTO[DEPARTAMENTO]
Ahora cada estancia es una ocurrencia distinta, identificada por el empleado y su fecha de inicio, y Ana puede tener dos estancias en Ventas.
💡 Consejo: Muchas veces el sistema necesita las dos cosas: consultar rápidamente el departamento actual y conservar la historia. Una solución habitual es mantener la relación actual 1:N (
trabaja) y la entidadESTANCIA, documentando la restricción de consistencia: “el departamento detrabajacoincide con el de la estancia vigente”.
7.4. Congelar el valor en el momento de la transacción
Hay datos que no queremos “historiar” en general, pero sí congelar en el momento en que se usan. El caso típico es el precio:
- El
preciode unPRODUCTOes el precio actual de catálogo. - El
precio_unitariode unaLINEA_PEDIDOes el precio al que se vendió, y no debe cambiar si mañana sube el catálogo.
Ambos atributos no son redundantes, aunque el día de la venta coincidan. Es exactamente el diseño del esquema EMPRESA (productos.precio y lineas_pedido.precio_unitario).
⚠️ Importante: Un error frecuente es eliminar el precio de la línea de pedido “porque ya está en el producto”. Si lo haces, al subir los precios cambiarían los importes de todas las facturas antiguas.
7.5. Tiempo válido y tiempo de transacción
En aplicaciones avanzadas (seguros, banca, sanidad) se distinguen dos tiempos:
- Tiempo válido (valid time): cuándo es cierto el hecho en la realidad (“Ana trabaja en Ventas desde el 1 de marzo”).
- Tiempo de transacción (transaction time): cuándo se registró en la base de datos (“lo grabamos el 15 de marzo”).
Una base de datos que registra ambos se llama bitemporal. En el modelo conceptual, si te piden los dos, modélalos como atributos explícitos (fecha_inicio_validez, fecha_fin_validez, fecha_registro, fecha_anulacion). Algunos SGBD ofrecen mecanismos específicos: Oracle, por ejemplo, permite declarar periodos de validez sobre una tabla (Temporal Validity) y consultar datos pasados con Flashback Query, pero son detalles de implementación que no cambian el modelo conceptual.
8. Relaciones N:M que deben admitir repetición
8.1. El problema
💻 Ejemplo: En un videoclub (o en una plataforma de alquiler digital), un socio alquila películas. Un socio puede alquilar muchas películas, una película puede alquilarse a muchos socios, y un mismo socio puede alquilar la misma película varias veces en fechas distintas.
El primer impulso es una relación N:M con la fecha como atributo:
flowchart LR
SOCIO[SOCIO] ---|"(0,n)"| alquila{"alquila<br/>N:M"}
alquila ---|"(0,n)"| PELICULA[PELICULA]
alquila --- a_fec([fecha])
alquila --- a_dev(["fecha_devolucion (0,1)"])
SOCIO --- s_id([<u>num_socio</u>])
PELICULA --- p_id([<u>cod_pelicula</u>])
Pero, por definición, una ocurrencia de una relación está determinada por las ocurrencias de las entidades que relaciona: en una relación binaria, cada par (socio, película) aparece como mucho una vez. Si Ana alquila Casablanca el 3 de marzo y otra vez el 20 de junio, el segundo alquiler no se puede registrar (o machacaría al primero).
| Socio | Película | Fecha | |
|---|---|---|---|
| Ana | Casablanca | 03/03/2026 | |
| Ana | Casablanca | 20/06/2026 | ← no admitido: el par (Ana, Casablanca) ya existe |
⚠️ Importante: El atributo
fechade la relación no forma parte de su identificación. Por eso no basta con ponerlo: la relación sigue identificada solo por (socio, película). Al pasar a tablas, la clave primaria sería (num_socio, cod_pelicula) y rechazaría el segundo alquiler.
8.2. Solución 1: convertir la relación en entidad
La solución más clara y la más usada es reificar la relación: convertir alquila en una entidad ALQUILER unida a SOCIO y a PELICULA con dos relaciones 1:N. Cada alquiler es una ocurrencia distinta, aunque se repita el par.
Con identificador propio (entidad fuerte):
flowchart LR
SOCIO[SOCIO] ---|"(1,1)"| realiza{"realiza<br/>1:N"}
realiza ---|"(0,n)"| ALQUILER[ALQUILER]
ALQUILER ---|"(0,n)"| de{"de<br/>1:N"}
de ---|"(1,1)"| PELICULA[PELICULA]
ALQUILER --- al_id([<u>num_alquiler</u>])
ALQUILER --- al_fec([fecha_alquiler])
ALQUILER --- al_dev(["fecha_devolucion (0,1)"])
ALQUILER --- al_imp([importe])
Como entidad débil de SOCIO, identificada por el socio + la película + la fecha (si no puede haber dos alquileres del mismo socio y película el mismo día):
flowchart LR
classDef debil stroke-width:4px
SOCIO[SOCIO] ---|"(1,1)"| realiza{"realiza<br/>ID"}:::debil
realiza ---|"(0,n)"| ALQUILER[ALQUILER]:::debil
ALQUILER ---|"(0,n)"| de{"de<br/>1:N"}
de ---|"(1,1)"| PELICULA[PELICULA]
ALQUILER --- al_fec(["<u>fecha_alquiler</u> parcial"])
ALQUILER --- al_dev(["fecha_devolucion (0,1)"])
En esta segunda versión, la película también forma parte de la identificación (la identificación completa sería socio + película + fecha). Algunos autores lo indican haciendo que de sea también relación de identificación; en cualquier caso, documéntalo en el diccionario.
| Opción | Ventajas | Inconvenientes |
|---|---|---|
Entidad fuerte con num_alquiler | Simple; admite cualquier repetición, incluso el mismo día; fácil de referenciar desde otras entidades (pagos, incidencias) | El identificador es artificial; hay que añadir una restricción si no se quieren duplicados reales |
| Entidad débil con fecha | El identificador refleja la realidad | Identificador largo; problemas si se puede repetir el mismo día |
8.3. Solución 2: añadir el tiempo como entidad (ternaria)
Otra solución clásica es considerar la FECHA como una entidad más y usar una relación ternaria SOCIO–PELICULA–FECHA. Cada ocurrencia de la relación queda determinada por el trío (socio, película, fecha), así que el par puede repetirse con fechas distintas. Esta solución es correcta desde el punto de vista formal y aparece en muchos libros, pero en la práctica se prefiere la reificación, porque la entidad FECHA no tiene atributos propios de interés y complica el diagrama. El cálculo de las cardinalidades de esta ternaria se explica en el módulo de relaciones ternarias.
8.4. Una pregunta previa: ¿qué se alquila exactamente?
En un videoclub físico, lo que se alquila no es la película (la obra), sino una copia concreta (el DVD número 3 de Casablanca). Si el enunciado habla de copias, inventario o estado de los soportes, el diseño correcto es:
flowchart LR
classDef debil stroke-width:4px
PELICULA[PELICULA] ---|"(1,1)"| tiene{"tiene<br/>ID"}:::debil
tiene ---|"(1,n)"| COPIA[COPIA]:::debil
COPIA --- co_num(["<u>num_copia</u> parcial"])
COPIA --- co_est([estado])
SOCIO[SOCIO] ---|"(1,1)"| realiza{"realiza<br/>1:N"}
realiza ---|"(0,n)"| ALQUILER[ALQUILER]
ALQUILER ---|"(0,n)"| de{"de<br/>1:N"}
de ---|"(1,1)"| COPIA
ALQUILER --- al_id([<u>num_alquiler</u>])
ALQUILER --- al_fec([fecha_alquiler])
ALQUILER --- al_dev(["fecha_devolucion (0,1)"])
Con restricciones como:
- R1: una copia no puede estar en dos alquileres sin devolver a la vez.
- R2: un socio no puede tener más de 3 alquileres sin devolver a la vez.
- R3: fecha_devolucion ≥ fecha_alquiler.
8.5. Cómo reconocer una relación con repetición
Hazte estas preguntas para cada relación N:M:
- ¿Puede repetirse el mismo par de ocurrencias en momentos distintos? (alquilar, comprar, visitar, consultar, examinarse, jugar…)
- ¿El hecho tiene fecha y es un acontecimiento más que un vínculo estable?
- ¿Interesa referenciar el hecho desde otras entidades (pagar un alquiler, reclamar una consulta)?
Si la respuesta a la 1 es sí, necesitas reificar (o una ternaria con el tiempo). Si las respuestas a la 2 o la 3 son sí, probablemente te convenga reificar aunque no haya repetición.
| Verbo del enunciado | Normalmente es | Ejemplo |
|---|---|---|
| “pertenece”, “trabaja en”, “está matriculado” (sin historia) | Vínculo estable → relación | Alumno matriculado en asignatura (un curso académico) |
| “alquila”, “compra”, “visita”, “consulta”, “reserva”, “juega” | Acontecimiento repetible → entidad | Alquiler, compra, visita, cita médica, reserva, partido |
| “ha trabajado en”, “ha vivido en” (con historia) | Vínculo con historia → entidad | Estancia, periodo de residencia |
9. Atributos derivados y redundancia controlada
9.1. Qué es un atributo derivado
📘 Concepto: Un atributo derivado es aquel cuyo valor puede calcularse a partir de otros datos del modelo. Se dibuja con borde discontinuo y debe llevar documentada su regla de derivación.
| Origen del cálculo | Ejemplo | Regla de derivación |
|---|---|---|
| Atributos de la misma ocurrencia | edad de una persona | Años completos entre fecha_nacimiento y hoy |
| Atributos de la misma ocurrencia | importe de una línea de pedido | cantidad × precio_unitario × (1 − descuento / 100) |
| Ocurrencias relacionadas (agregado) | num_empleados de un departamento | Número de empleados relacionados por trabaja |
| Ocurrencias relacionadas (agregado) | importe_total de un pedido | Suma del importe de sus líneas |
| Ocurrencias relacionadas (valor) | ultima_fecha_compra de un cliente | Máxima fecha de sus pedidos |
| El tiempo | antiguedad de un empleado | Años desde fecha_alta |
flowchart LR
classDef debil stroke-width:4px
classDef derivado stroke-dasharray: 5 5
PEDIDO[PEDIDO] --- p_id([<u>num_pedido</u>])
PEDIDO --- p_fec([fecha])
PEDIDO --- p_tot([importe_total]):::derivado
PEDIDO ---|"(1,1)"| contiene{"contiene<br/>ID"}:::debil
contiene ---|"(1,n)"| LINEA[LINEA_PEDIDO]:::debil
LINEA --- l_num(["<u>num_linea</u> parcial"])
LINEA --- l_can([cantidad])
LINEA --- l_pre([precio_unitario])
LINEA --- l_des([descuento])
LINEA --- l_imp([importe]):::derivado
9.2. ¿Se dibuja o no?
En el modelo conceptual, incluir un atributo derivado es una decisión de documentación, no de almacenamiento: dibujarlo dice “este dato es importante para el usuario y se calcula así”. En los diseños lógico y físico se decide si se almacena o se calcula cada vez:
| Criterio | Calcular cada vez | Almacenar |
|---|---|---|
| Frecuencia de consulta | Baja | Muy alta |
| Coste del cálculo | Bajo (operación sobre la misma fila) | Alto (agregados sobre muchas filas) |
| Frecuencia de cambio de los datos de origen | Alta | Baja |
| Riesgo de inconsistencia | Ninguno | Hay que mantenerlo sincronizado |
| Datos que dependen de “hoy” (edad, antigüedad) | Casi siempre calcular | Nunca almacenar (caducan solos) |
💡 Consejo: En Oracle, un derivado de la misma fila puede implementarse sin redundancia como columna virtual (
importe GENERATED ALWAYS AS (cantidad * precio_unitario * (1 - descuento / 100)) VIRTUAL) o en una vista. Los agregados se resuelven con vistas, vistas materializadas o triggers. Lo verás en los módulos de DDL.
9.3. Redundancia que no es derivación
No confundas un atributo derivado con uno que coincide con otro en un momento dado pero tiene significado distinto. Ya hemos visto dos casos:
precio_unitariode la línea frente apreciodel producto (sección 7.4): no es derivado.- Comercial que gestionó el pedido frente a comercial asignado al cliente (sección 6.5): no es derivado.
La pregunta que lo distingue es: “¿si cambia el dato de origen, debe cambiar este?”. Si la respuesta es sí, es derivado. Si es no, es un dato independiente.
10. Restricciones de integridad de negocio
10.1. El catálogo de restricciones
Al terminar el diseño conceptual, todas las restricciones que no estén en el diagrama deben quedar recogidas en un catálogo, con un identificador, un enunciado en lenguaje natural, los elementos afectados y, si ya se conoce, la forma prevista de implementación. Este catálogo forma parte del diccionario de datos (módulo 14).
Reglas para redactar bien una restricción:
- Atómica: una restricción, una idea. “El precio es positivo y el stock no es negativo” son dos restricciones.
- Verificable: debe poder comprobarse sobre los datos. Evita “razonable”, “adecuado”, “normalmente”.
- Con los nombres del modelo: usa los nombres exactos de entidades, atributos y relaciones del diagrama.
- Sin decidir la implementación: “el saldo no puede ser negativo”, no “poner un CHECK en la tabla de cuentas”. La implementación es una columna aparte.
- Con su origen: de qué requisito o entrevista procede, para poder validarla con el usuario.
Una plantilla útil: “[Elemento] [debe / no puede] [condición] [cuando / salvo que …]”.
10.2. Ejemplo completo: catálogo de un videoclub
Para el modelo de la sección 8.4 (película, copia, socio, alquiler) más una entidad TARIFA:
| Id | Restricción | Elementos | Tipo | Implementación prevista |
|---|---|---|---|---|
| R1 | El año de una película está entre 1888 y el año actual | PELICULA.anio | Dominio | CHECK (con límite fijo) o aplicación |
| R2 | El estado de una copia es ‘BUENO’, ‘DAÑADO’ o ‘BAJA’ | COPIA.estado | Dominio | CHECK ... IN (...) |
| R3 | El email de un socio es único | SOCIO.email | Unicidad | UNIQUE |
| R4 | fecha_devolucion ≥ fecha_alquiler | ALQUILER | Entre atributos | CHECK de tabla |
| R5 | El importe de un alquiler es mayor que 0 | ALQUILER.importe | Dominio | CHECK |
| R6 | Una copia en estado ‘BAJA’ no puede alquilarse | ALQUILER, COPIA.estado | Entre entidades | Trigger o aplicación |
| R7 | Una copia no puede estar en dos alquileres sin devolver a la vez | ALQUILER | Entre ocurrencias | Trigger o aplicación (o índice único basado en función) |
| R8 | Un socio no puede tener más de 3 alquileres sin devolver | ALQUILER, SOCIO | Cardinalidad condicionada | Trigger o aplicación |
| R9 | Un socio con alquileres con más de 30 días de retraso no puede alquilar | ALQUILER, SOCIO | Negocio | Aplicación |
| R10 | El importe de un alquiler es el de la tarifa vigente en su fecha | ALQUILER, TARIFA | Derivación / temporal | Aplicación (y conservar el importe en el alquiler) |
| R11 | Los periodos de vigencia de las tarifas no se solapan | TARIFA | Entre ocurrencias / temporal | Trigger o aplicación |
| R12 | Una película no puede borrarse si tiene alquileres | PELICULA, ALQUILER | Referencial | Clave ajena sin ON DELETE CASCADE |
💡 Consejo: Fíjate en la última columna: solo una parte de las restricciones se implementa de forma declarativa (
CHECK,UNIQUE,NOT NULL,FOREIGN KEY). El resto requiere triggers (que se estudian en el Curso de Oracle PL/SQL) o lógica en la aplicación. El estándar SQL define además las aserciones (CREATE ASSERTION), restricciones generales sobre varias tablas, pero tradicionalmente los SGBD comerciales no las han implementado; comprueba la documentación de tu versión antes de contar con ellas.
10.3. Clasificación según la implementación
| Mecanismo | Qué puede garantizar | Ejemplos del catálogo |
|---|---|---|
Tipo de dato y NOT NULL | Dominio básico y obligatoriedad | — |
CHECK de columna o de tabla | Condiciones sobre una sola fila | R2, R4, R5 |
UNIQUE / PRIMARY KEY | Unicidad de valores | R3 |
FOREIGN KEY y acciones referenciales | Existencia de la ocurrencia referenciada; comportamiento al borrar | R12 |
| Índice único sobre expresión | Unicidad condicionada (“solo un alquiler abierto por copia”) | R7 (técnica avanzada) |
| Trigger | Condiciones sobre varias filas o tablas, transiciones de estado | R6, R7, R8, R11 |
| Aplicación | Reglas complejas, cambiantes o que dependen de contexto externo | R9, R10 |
⚠️ Importante: Una restricción implementada solo en la aplicación puede saltarse con cualquier herramienta que acceda directamente a la base de datos (un script SQL, otra aplicación). Siempre que sea posible, implementa las restricciones en la base de datos, y deja en la aplicación solo las que no se puedan garantizar allí. En cualquier caso, el catálogo del modelo conceptual debe recogerlas todas, se implementen donde se implementen.
11. Ejercicios
Ejercicio 1: Identificar el tipo de restricción entre relaciones
Para cada enunciado, indica si se trata de exclusividad, exclusión, inclusividad o inclusión, y dibuja el fragmento de diagrama con la notación del curso:
- Un piloto de una aerolínea solo puede ser comandante de un modelo de avión en el que haya sido antes copiloto.
- Un artículo científico se publica en una revista o en las actas de un congreso, pero no en ambas.
- Un revisor de un congreso no puede revisar un artículo del que es autor.
- Para ser tutor de alumnos en prácticas, un empleado tiene que haber completado al menos 3 cursos de formación.
Ver solución
1. Inclusión. El par (piloto, modelo) de comandante debe estar en copiloto: no basta con haber sido copiloto de cualquier modelo.
flowchart LR
PILOTO[PILOTO] ---|"(0,n)"| copiloto{"copiloto<br/>N:M"}
copiloto ---|"(0,n)"| MODELO[MODELO_AVION]
PILOTO ---|"(0,n)"| comandante{"comandante<br/>N:M"}
comandante ---|"(0,n)"| MODELO
comandante -.->|"inclusión"| copiloto
2. Exclusividad (total, si todo artículo se publica en algún sitio; parcial si puede haber artículos no publicados). Afecta a cada ocurrencia de ARTICULO, que participa en una relación u otra.
flowchart LR
ARTICULO[ARTICULO] ---|"(0,n)"| en_rev{"publicado_en<br/>1:N"}
en_rev ---|"(0,1)"| REVISTA[REVISTA]
ARTICULO ---|"(0,n)"| en_con{"presentado_en<br/>1:N"}
en_con ---|"(0,1)"| CONGRESO[CONGRESO]
en_rev -.-|"exclusividad"| en_con
3. Exclusión. Un investigador puede ser autor de unos artículos y revisor de otros; lo prohibido es el mismo par (investigador, artículo) en las dos relaciones.
flowchart LR
INVESTIGADOR[INVESTIGADOR] ---|"(1,n)"| escribe{"escribe<br/>N:M"}
escribe ---|"(0,n)"| ARTICULO[ARTICULO]
INVESTIGADOR ---|"(0,n)"| revisa{"revisa<br/>N:M"}
revisa ---|"(0,n)"| ARTICULO
escribe -.-|"exclusión"| revisa
4. Inclusividad (3,n). Importa cuántos cursos ha completado el empleado, no cuáles.
flowchart LR
EMPLEADO[EMPLEADO] ---|"(0,1)"| tutoriza{"tutoriza<br/>1:N"}
tutoriza ---|"(0,n)"| ALUMNO[ALUMNO_PRACTICAS]
EMPLEADO ---|"(0,n)"| completa{"completa<br/>N:M"}
completa ---|"(0,n)"| CURSO[CURSO]
tutoriza -.->|"inclusividad (3,n)"| completa
Cada alumno en prácticas tiene 0 o 1 tutor (0,1) junto a EMPLEADO; un empleado tutoriza de 0 a n alumnos.
Ejercicio 2: Detectar y resolver trampas
Un hospital ha modelado lo siguiente: cada PLANTA tiene varias HABITACIONes (1:N); cada PLANTA tiene asignados varios ENFERMEROs (1:N); cada PACIENTE ingresado puede estar asignado a un ENFERMERO responsable (0..1) y cada enfermero atiende a varios pacientes. Se quieren responder estas preguntas: (a) ¿en qué habitación trabaja el enfermero X?; (b) ¿en qué planta está ingresado el paciente Y? Analiza qué trampas hay y propón un diagrama corregido. Supón que cada enfermero trabaja en una planta (no en una habitación concreta) y que cada paciente ocupa una habitación.
Ver solución
Pregunta (a): no es una trampa de abanico, sino una pregunta mal planteada: el enfermero trabaja en una planta, no en una habitación. El abanico PLANTA → HABITACION / PLANTA → ENFERMERO es correcto porque el negocio no relaciona enfermeros con habitaciones. Es importante distinguir “el modelo no responde porque falta información” de “el modelo no responde porque la pregunta no tiene sentido en la realidad”.
Pregunta (b): trampa de sima. El único camino del paciente a la planta es PACIENTE → ENFERMERO → PLANTA, y la participación del paciente en la relación con el enfermero es opcional. Para los pacientes sin enfermero asignado no podemos saber la planta. Además falta la información esencial: la habitación del paciente.
Diagrama corregido:
flowchart LR
PLANTA[PLANTA] ---|"(1,1)"| tiene{"tiene<br/>1:N"}
tiene ---|"(1,n)"| HABITACION[HABITACION]
PLANTA ---|"(1,1)"| asignado{"asignado<br/>1:N"}
asignado ---|"(1,n)"| ENFERMERO[ENFERMERO]
HABITACION ---|"(1,1)"| ocupa{"ocupa<br/>1:N"}
ocupa ---|"(0,n)"| PACIENTE[PACIENTE]
ENFERMERO ---|"(0,1)"| responsable{"responsable<br/>1:N"}
responsable ---|"(0,n)"| PACIENTE
Ahora la planta del paciente se obtiene por PACIENTE → HABITACION → PLANTA, que no tiene mínimos 0 en ese sentido. Aparece un ciclo (PLANTA–HABITACION–PACIENTE–ENFERMERO–PLANTA) que hay que analizar: si el negocio exige que el enfermero responsable trabaje en la planta del paciente, se anota R1: el enfermero responsable de un paciente está asignado a la planta de la habitación que ocupa el paciente.
(Si interesa la historia de ingresos, ocupa debería convertirse en una entidad INGRESO con fechas, por las razones de la sección 8.)
Ejercicio 3: Analizar ciclos
Para cada ciclo, indica si alguna relación es redundante, si hay una restricción de caminos coincidentes o si el ciclo es independiente:
CIUDAD–está_en (N:1)–PROVINCIA–está_en (N:1)–COMUNIDAD; yCIUDAD–pertenece (N:1)–COMUNIDAD.EMPLEADO–trabaja (N:1)–DEPARTAMENTO;EMPLEADO–participa (N:M)–PROYECTO;PROYECTO–gestionado_por (N:1)–DEPARTAMENTO.JUGADOR–juega_en (N:1)–EQUIPO;EQUIPO–compite_en (N:1)–LIGA;JUGADOR–inscrito_en (N:1)–LIGA.
Ver solución
-
Redundante. Cada ciudad está en una provincia, y cada provincia en una comunidad: la comunidad de la ciudad se deduce siempre.
CIUDAD pertenece COMUNIDADdebe eliminarse. -
Independiente (salvo regla del negocio). Un empleado puede participar en proyectos gestionados por otros departamentos. Ninguna relación se deduce de las otras. Si el negocio dijera “solo se participa en proyectos del propio departamento”, sería una restricción de caminos coincidentes; si dijera “al menos el director del proyecto es del departamento gestor”, sería otra restricción distinta. Así es en el esquema EMPRESA:
ASIGNACIONESpermite asignar empleados de cualquier departamento a cualquier proyecto. -
Depende del tiempo y del negocio. Si un jugador solo está en un equipo y el equipo en una liga,
inscrito_enparece redundante. Pero en muchas competiciones un jugador puede estar inscrito en una liga sin equipo (agente libre), o los traspasos de mitad de temporada hacen que la inscripción y el equipo actual no coincidan. Siinscrito_ensiempre coincide conjuega_en+compite_en, es redundante; si no, el ciclo se mantiene con una restricción (“si un jugador juega en un equipo, está inscrito en la liga de ese equipo”).
Ejercicio 4: Historia de precios
Una cadena de gasolineras quiere guardar el precio de cada combustible (gasóleo A, sin plomo 95…) en cada estación de servicio. Los precios cambian varias veces al día, y se necesita saber qué precio tenía cada combustible en cada estación en cualquier momento del pasado, además de las ventas realizadas (fecha y hora, litros, combustible, estación, importe cobrado). Dibuja el diagrama y escribe las restricciones necesarias.
Ver solución
El precio depende del combustible y de la estación y del momento: se modela como entidad.
flowchart TB
ESTACION[ESTACION] --- e_id([<u>cod_estacion</u>])
ESTACION --- e_dir([direccion])
COMBUSTIBLE[COMBUSTIBLE] --- c_id([<u>cod_combustible</u>])
COMBUSTIBLE --- c_nom([nombre])
PRECIO[PRECIO] --- pr_id([<u>id_precio</u>])
PRECIO --- pr_ini([inicio_vigencia])
PRECIO --- pr_fin(["fin_vigencia (0,1)"])
PRECIO --- pr_imp([precio_litro])
ESTACION ---|"(1,1)"| fija{"fija<br/>1:N"}
fija ---|"(0,n)"| PRECIO
PRECIO ---|"(0,n)"| para{"para<br/>1:N"}
para ---|"(1,1)"| COMBUSTIBLE
VENTA[VENTA] --- v_id([<u>num_venta</u>])
VENTA --- v_fh([fecha_hora])
VENTA --- v_lit([litros])
VENTA --- v_imp([importe])
ESTACION ---|"(1,1)"| en{"en<br/>1:N"}
en ---|"(0,n)"| VENTA
VENTA ---|"(0,n)"| de{"de<br/>1:N"}
de ---|"(1,1)"| COMBUSTIBLE
Restricciones:
- R1: fin_vigencia > inicio_vigencia.
- R2: para una misma estación y combustible, los periodos de vigencia de los precios no se solapan.
- R3: para una misma estación y combustible hay como mucho un precio vigente (sin fin_vigencia).
- R4: litros > 0 e importe > 0.
- R5: el importe de una venta es litros × precio_litro del precio vigente en
fecha_horapara esa estación y combustible (se guarda el importe cobrado, que es un dato congelado y puede incluir redondeos o descuentos; la regla sirve para validar).
Decisiones discutibles:
PRECIOpodría ser entidad débil deESTACIONyCOMBUSTIBLEconinicio_vigenciacomo identificador parcial. Es igual de correcto; se ha preferido un identificador propio por simplicidad.- No se relaciona
VENTAconPRECIO: el precio aplicado se deduce por fechas, y además el importe cobrado se conserva.
Ejercicio 5: Relación con repetición
Un gimnasio registra las sesiones a las que asiste cada socio: un socio puede asistir muchas veces a la misma actividad (spinning, yoga…), incluso dos veces el mismo día (mañana y tarde). Cada asistencia tiene una hora de entrada y una valoración opcional (1 a 5). Además, cada actividad la imparte en cada sesión un monitor. Dibuja el diagrama.
Ver solución
La clave está en reconocer que hay dos acontecimientos: la sesión (una actividad impartida un día a una hora por un monitor) y la asistencia de un socio a una sesión.
flowchart TB
classDef debil stroke-width:4px
ACTIVIDAD[ACTIVIDAD] --- a_id([<u>cod_actividad</u>])
ACTIVIDAD --- a_nom([nombre])
ACTIVIDAD ---|"(1,1)"| programa{"programa<br/>ID"}:::debil
programa ---|"(0,n)"| SESION[SESION]:::debil
SESION --- s_fh(["<u>fecha_hora_inicio</u> parcial"])
SESION --- s_sal([sala])
MONITOR[MONITOR] ---|"(1,1)"| imparte{"imparte<br/>1:N"}
imparte ---|"(0,n)"| SESION
SOCIO[SOCIO] ---|"(0,n)"| asiste{"asiste<br/>N:M"}
asiste ---|"(0,n)"| SESION
asiste --- as_ent([hora_entrada])
asiste --- as_val(["valoracion (0,1)"])
SOCIO --- so_id([<u>num_socio</u>])
Con SESION como entidad, la relación asiste entre SOCIO y SESION ya no necesita repetición: un socio asiste como mucho una vez a cada sesión concreta; las repeticiones de la actividad son sesiones distintas. Este es un patrón muy útil: a veces la repetición desaparece si identificas el acontecimiento que faltaba.
Restricciones:
- R1: valoracion entre 1 y 5.
- R2: un monitor no puede impartir dos sesiones que se solapen en el tiempo (necesita la duración de la actividad).
- R3: el número de asistentes a una sesión no supera el aforo de la sala.
Ejercicio 6: Catálogo de restricciones
Redacta un catálogo de al menos 8 restricciones para el siguiente fragmento, indicando el tipo y la implementación prevista: un hotel tiene HABITACION (número, tipo, precio_noche, capacidad), CLIENTE (dni, nombre, fecha_nacimiento, email) y RESERVA (número, fecha_entrada, fecha_salida, num_huespedes, importe, estado), con cada reserva de un cliente para una habitación.
Ver solución
| Id | Restricción | Tipo | Implementación |
|---|---|---|---|
| R1 | El tipo de una habitación es ‘INDIVIDUAL’, ‘DOBLE’ o ‘SUITE’ | Dominio | CHECK ... IN |
| R2 | precio_noche > 0 | Dominio | CHECK |
| R3 | capacidad entre 1 y 6 | Dominio | CHECK |
| R4 | El email del cliente es único | Unicidad | UNIQUE |
| R5 | fecha_salida > fecha_entrada | Entre atributos | CHECK de tabla |
| R6 | num_huespedes ≥ 1 y no supera la capacidad de la habitación reservada | Entre entidades | Trigger o aplicación (la primera parte, CHECK) |
| R7 | Dos reservas no canceladas de la misma habitación no pueden solaparse en fechas | Entre ocurrencias / temporal | Trigger o aplicación |
| R8 | El cliente titular de una reserva es mayor de edad en la fecha de entrada | Entre entidades / temporal | Trigger o aplicación |
| R9 | El estado de una reserva es ‘CONFIRMADA’, ‘CANCELADA’, ‘EN_CURSO’ o ‘FINALIZADA’ | Dominio | CHECK ... IN |
| R10 | Una reserva ‘FINALIZADA’ o ‘CANCELADA’ no puede volver a ‘CONFIRMADA’ | Transición | Trigger o aplicación |
| R11 | El importe se calcula como noches × precio_noche vigente al confirmar, y no cambia aunque cambie el precio de la habitación | Derivación / temporal | Aplicación; el importe se almacena (dato congelado) |
Fíjate en R8: necesita la fecha de nacimiento del cliente y la fecha de entrada de la reserva, es decir, dos entidades. No puede ser un CHECK. Y en R11: el importe no es un atributo derivado en sentido estricto, porque no debe recalcularse si cambia el precio.
Ejercicio 7 (propuesto): Biblioteca con restricciones
Diseña el modelo de préstamos de una biblioteca (libros, ejemplares, socios, préstamos y reservas) con las siguientes reglas, y decide para cada una si se recoge en el diagrama (y cómo) o en el catálogo: un socio puede reservar un libro (no un ejemplar) solo si no hay ningún ejemplar disponible; un socio no puede reservar un libro que ya tiene prestado; un socio sancionado no puede pedir préstamos; un ejemplar de consulta en sala no se presta nunca; la duración máxima de un préstamo es de 15 días para alumnos y 30 para profesores.
Ejercicio 8 (propuesto): Trayectoria de un futbolista
Modela la trayectoria completa de los jugadores de una federación: equipos en los que han jugado (con posibilidad de volver a un equipo anterior), cesiones (un jugador pertenece a un equipo pero juega cedido en otro durante una temporada), dorsal en cada equipo y temporada, y goles marcados en cada partido. Identifica todas las relaciones con repetición, las restricciones temporales y los posibles ciclos, y justifica cómo los resuelves.
Resumen
| Concepto | Idea clave | Representación / tratamiento |
|---|---|---|
| Restricción explícita | Regla que el diagrama no puede expresar | Nota R1... en el diagrama y catálogo del diccionario |
| Exclusividad | Cada ocurrencia participa en una u otra relación | r1 -.-\|"exclusividad"\| r2 |
| Exclusión | El mismo par no puede estar en las dos relaciones | r1 -.-\|"exclusión"\| r2 |
| Inclusividad | Para participar en R2 hay que haber participado (mín, máx) veces en R1 | r2 -.->\|"inclusividad (mín,máx)"\| r1 |
| Inclusión | R2 ⊆ R1: el mismo par debe estar en R1 | r2 -.->\|"inclusión"\| r1 |
| Reflexivas | Irreflexividad, aciclicidad, simetría, profundidad | Notas en el diagrama |
| Trampa de abanico | Dos 1:N desde la misma entidad: camino ambiguo | Reestructurar las relaciones |
| Trampa de sima | Participación opcional en el camino: camino interrumpido | Añadir la relación directa |
| Ciclo | Camino cerrado de relaciones | Analizar: redundante, caminos coincidentes o independiente |
| Redundancia controlada | Dato deducible que se mantiene a propósito | Justificar, documentar y garantizar su consistencia |
| Atributo histórico | Interesan los valores pasados | Entidad de historial débil con periodo de vigencia |
| Relación histórica | 1:N actual se convierte en N:M en el tiempo | Entidad con fechas (estancia, periodo) |
| Dato congelado | Valor fijado en el momento de la transacción | Atributo propio, no derivado (precio_unitario) |
| N:M con repetición | El mismo par se repite en el tiempo | Reificar la relación en una entidad |
| Atributo derivado | Se calcula a partir de otros datos | Borde discontinuo + regla de derivación |
| Catálogo de restricciones | Lista atómica y verificable de reglas | Id, enunciado, elementos, tipo, implementación |