</>waridocu

Bases de datos

Los símbolos: #, * y o

Qué significan exactamente el numeral, el asterisco y la o minúscula delante de cada atributo en la notación Barker, qué es un UID y cómo elegirlo bien.

bases-de-datosbarkeruidclave-primarianotaciondata-modeler

Tres símbolos, tres preguntas

En la notación Barker —la que Data Modeler usa por defecto en el modelo lógico— cada atributo lleva delante un símbolo. No son decoración: cada uno responde una pregunta distinta sobre ese dato.

texttext
┌──────────────────────────┐
│ ALUMNO                   │
├──────────────────────────┤
│ # id_alumno              │   ← identifica a la instancia
│ * nombre                 │   ← obligatorio
│ * email                  │   ← obligatorio
│ o telefono               │   ← opcional
│ o fecha_nacimiento       │   ← opcional
└──────────────────────────┘
SímboloSe leeSignificaAl pasar a tabla
#numeral, hashForma parte del identificador único (UID)PRIMARY KEY
*asteriscoObligatorio: toda instancia tiene que tener un valorNOT NULL
oo minúsculaOpcional: puede no tener valorAcepta NULL

Esa última columna es la razón por la que vale la pena aprenderlos bien: no son anotaciones informales, son decisiones que la base de datos va a hacer cumplir. Un * mal puesto es un NOT NULL que después rechaza filas legítimas; un * que faltó es una columna que se llena de vacíos.

Nota

La o viene de optional. Que el símbolo del atributo opcional sea una letra y no un signo de puntuación es raro al principio, pero tiene una ventaja práctica: en una lista de veinte atributos, los * y los # saltan a la vista y las o se hunden en el fondo — que es exactamente el orden de importancia que tienen.

El asterisco: obligatorio

* significa que toda instancia de esta entidad debe tener un valor para ese atributo. No “casi siempre lo tiene”: siempre, sin excepción, o la instancia no se puede guardar.

La prueba para decidirlo es concreta: piensa en un caso real que no tenga ese dato. Si se te ocurre uno, el atributo es opcional.

Atributo de ALUMNO¿Existe un alumno sin esto?Símbolo
nombreNo, un alumno sin nombre no es un alumno*
emailDepende del negocio: si la inscripción es online, no*
telefonoSí, muchos no lo dano
fecha_egresoSí, todos los que todavía cursano

Ese fecha_egreso ilustra el caso más frecuente de atributo opcional: un dato que se conoce recién más adelante. Marcarlo * haría imposible cargar un alumno el día que se inscribe.

Advertencia

Ante la duda, marca o. Pasar un atributo de opcional a obligatorio más adelante es fácil (se completan los que faltan y se agrega la restricción); al revés también es fácil, pero mientras tanto el sistema estuvo rechazando datos válidos o, peor, la gente los estuvo rellenando con basura —"sin datos", "-", "n/a"— para poder guardar. Esa basura después ensucia todas las consultas.

El numeral: el identificador único (UID)

# marca los atributos que forman el identificador único — el UID (unique identifier): el dato que permite señalar una instancia y solo una, sin ambigüedad.

Es la pieza más importante del modelo. Sin UID, dos alumnos llamados “Ana Ruiz” son indistinguibles, y ninguna otra entidad puede referirse a uno de los dos.

texttext
┌──────────────────────────┐
│ CURSO                    │
├──────────────────────────┤
│ # codigo                 │   "JAV-01" identifica a este curso y a ninguno más
│ * nombre                 │
│ * horas                  │
└──────────────────────────┘

Un UID debe cumplir tres condiciones:

CondiciónQué significaContraejemplo
ÚnicoNo hay dos instancias con el mismo valornombre — hay dos “Ana Ruiz”
ObligatorioNunca puede faltaremail si algunos alumnos no dan uno
EstableNo cambia con el tiempoemail — la gente lo cambia
Importante

Un atributo # es obligatorio por definición: no tiene sentido identificar algo con un dato que puede faltar. Por eso en la notación Barker el # reemplaza al *, no se escriben los dos. En Data Modeler el atributo aparece marcado a la vez como parte del UID y como obligatorio, y esa doble marca es correcta — es lo mismo que dice el #.

UID compuesto: varios atributos juntos

A veces ningún atributo alcanza solo, pero la combinación de dos sí:

texttext
┌──────────────────────────┐
│ AULA                     │
├──────────────────────────┤
│ # edificio               │   "A" solo no alcanza: hay un 12 en cada edificio
│ # numero                 │   "12" solo tampoco
│ * capacidad              │   pero ("A", 12) identifica un aula y solo una
└──────────────────────────┘

Los dos llevan # porque los dos forman parte del identificador. Al pasar a tabla, eso se convierte en una clave primaria compuesta por dos columnas.

UID natural o artificial

Aquí hay una decisión de diseño real, con argumentos de los dos lados:

UID naturalUID artificial (surrogate)
Qué esUn dato que ya existe en el negocioUn número inventado sin significado
Ejemplodni, isbn, codigo de cursoid_alumno autoincremental
A favorSignifica algo; no hay datos de másNunca cambia; siempre está; siempre es único
En contraPuede cambiar, faltar o repetirseNo significa nada para nadie

Los casos que hacen fallar a un UID natural aparecen siempre, y son más comunes de lo que parece: un DNI que estaba mal cargado y hay que corregir, un extranjero que no tiene, dos productos a los que el proveedor asignó el mismo código por error. Cuando eso pasa, cambiar el UID es carísimo, porque su valor está copiado en todas las tablas que lo referencian.

Tip

La práctica más extendida hoy es usar un UID artificial (id_alumno) y, si además existe un dato naturalmente único como el DNI, marcarlo como unique pero sin que sea el identificador. Así ganas la estabilidad del artificial sin renunciar a que la base impida DNIs repetidos. Este es el criterio que sigue el resto de la sección.

La o minúscula: opcional

o es simplemente lo contrario de *: el atributo puede no tener valor. Al pasar a tabla, la columna acepta NULL.

Y NULL merece una advertencia propia, porque es la fuente de sorpresas más común al consultar una base de datos:

Advertencia

NULL no es cero, ni cadena vacía, ni false: significa “no se sabe”. Y eso cambia cómo se comporta en las consultas. WHERE telefono != '555-1234' no devuelve las filas donde telefono es NULL, porque comparar con algo desconocido no da ni verdadero ni falso. Para esas filas hay que preguntar explícitamente con IS NULL. Cada o que pones en el modelo es un lugar donde después habrá que acordarse de esto.

El modelo del instituto, ahora con símbolos

Aplicando todo lo anterior al enunciado:

texttext
┌──────────────────────┐   ┌──────────────────────┐   ┌──────────────────────┐
│ ALUMNO               │   │ CURSO                │   │ PROFESOR             │
├──────────────────────┤   ├──────────────────────┤   ├──────────────────────┤
│ # id_alumno          │   │ # codigo             │   │ # id_profesor        │
│ * nombre             │   │ * nombre             │   │ * nombre             │
│ * email              │   │ * horas              │   │ * email              │
│ o telefono           │   │ o descripcion        │   │ o telefono           │
└──────────────────────┘   └──────────────────────┘   └──────────────────────┘

Justificando cada decisión, que es lo que se te va a pedir defender:

  • id_alumno e id_profesor son artificiales. No hay ningún dato natural del enunciado que sea único, obligatorio y estable a la vez.
  • codigo de CURSO sí es natural. El instituto ya usa “JAV-01” para identificar sus cursos: es un identificador que existe en el negocio y no hace falta inventar otro.
  • telefono es o en las dos entidades porque el enunciado dice literalmente “opcionalmente su teléfono” para el profesor, y para el alumno vale el mismo criterio.
  • descripcion es o porque un curso se puede dar de alta antes de haber redactado su descripción.

Pon a prueba

🎯 ¿Cuál es el mejor UID?

Una tienda online guarda de cada cliente: nombre, apellido, email, teléfono y fecha de registro. ¿Cuál es el mejor identificador único?

  • Es único, pero falla en las otras dos condiciones: la gente cambia de email, y no todo cliente da uno. Un UID que puede cambiar obliga a actualizar en cascada todas las tablas que lo referencian.

  • Un UID compuesto es perfectamente válido cuando la combinación es realmente única, pero esta no lo es: dos personas distintas pueden llamarse igual, y ese caso llega tarde o temprano. Además los nombres se corrigen (un error de tipeo, un cambio legal).

  • Correcto. El id_cliente cumple las tres condiciones sin depender de nada del negocio: nunca cambia, nunca falta, nunca se repite. Y marcar email como único conserva la garantía de que no haya dos cuentas con el mismo correo, sin cargar esa responsabilidad sobre el identificador.

  • Falla en las tres condiciones a la vez: no todos dan teléfono (no es obligatorio), la gente cambia de número (no es estable), y una familia puede compartir la línea (no es único).

✏️ Pon los símbolos

Un hospital registra pacientes. La historia clínica es el número que el hospital ya usa para identificarlos. El nombre y la fecha de nacimiento se piden siempre; la obra social y el teléfono, no. Escribe el símbolo (#, * u o) delante de cada atributo.

PACIENTE
 nro_historia_clinica
 nombre
 fecha_nacimiento
 obra_social
 telefono

💡 Corrige el modelo

Este modelo tiene cuatro errores en el uso de los símbolos. ¿Cuáles son?

texttext
┌────────────────────────────────┐
│ PEDIDO                         │
├────────────────────────────────┤
│ o nro_pedido                   │
│ * fecha_entrega                │
│ # email_cliente                │
│ o fecha_pedido                 │
└────────────────────────────────┘

1. o nro_pedido. Es lo que identifica a un pedido, así que debería ser #. Un identificador nunca puede ser opcional: no se puede señalar una instancia con un dato que puede faltar.

2. * fecha_entrega. Marcarla obligatoria hace imposible cargar un pedido que todavía no se entregó — o sea, todos los pedidos nuevos. Es el ejemplo clásico de dato que se conoce más adelante: debe ser o.

3. # email_cliente. Dos errores en uno. Como UID falla en las tres condiciones (cambia, puede faltar, un cliente hace varios pedidos con el mismo email, así que ni siquiera es único por pedido). Y además el cliente no debería estar como atributo suelto de PEDIDO: es una entidad aparte, vinculada por una relación.

4. o fecha_pedido. Todo pedido se hace en un momento determinado y ese dato se conoce en el instante mismo en que se crea. Debe ser *.

Corregido:

texttext
┌────────────────────────────────┐
│ PEDIDO                         │
├────────────────────────────────┤
│ # nro_pedido                   │
│ * fecha_pedido                 │
│ o fecha_entrega                │
└────────────────────────────────┘

     └── relación hacia CLIENTE (próxima página)

Siguiente paso

Las entidades ya están completas por dentro. Falta lo que las une: las líneas entre cajas, con su pata de gallo, su tramo continuo y su tramo punteado — cada uno de esos detalles significa algo preciso — ver Relaciones y cardinalidad.