academia/docs/entregables/02-diseno/base-datos/DI-003-diseno-base-datos.md

199 lines
8.1 KiB
Markdown
Raw Normal View History

# DI-003: Diseño de Base de Datos
**Proyecto:** Sistema de Registro de Estudiantes
**Fecha:** 2026-01-07
---
## 1. Modelo Entidad-Relación
```
┌─────────────────────────────────────────────────────────────────┐
│ PROFESSORS │
├──────────────┬────────────────┬─────────────────────────────────┤
│ Id │ INT │ PK, IDENTITY │
│ Name │ NVARCHAR(100) │ NOT NULL │
└──────────────┴────────────────┴─────────────────────────────────┘
│ 1:N (cada profesor → 2 materias)
┌─────────────────────────────────────────────────────────────────┐
│ SUBJECTS │
├──────────────┬────────────────┬─────────────────────────────────┤
│ Id │ INT │ PK, IDENTITY │
│ Name │ NVARCHAR(100) │ NOT NULL │
│ Credits │ INT │ DEFAULT 3, CHECK (Credits = 3) │
│ ProfessorId │ INT │ FK → Professors.Id │
└──────────────┴────────────────┴─────────────────────────────────┘
│ 1:N
┌─────────────────────────────────────────────────────────────────┐
│ ENROLLMENTS │
├──────────────┬────────────────┬─────────────────────────────────┤
│ Id │ INT │ PK, IDENTITY │
│ StudentId │ INT │ FK → Students.Id │
│ SubjectId │ INT │ FK → Subjects.Id │
│ EnrolledAt │ DATETIME2 │ DEFAULT GETUTCDATE() │
└──────────────┴────────────────┴─────────────────────────────────┘
│ 0..3:N
┌─────────────────────────────────────────────────────────────────┐
│ STUDENTS │
├──────────────┬────────────────┬─────────────────────────────────┤
│ Id │ INT │ PK, IDENTITY │
│ Name │ NVARCHAR(100) │ NOT NULL │
│ Email │ NVARCHAR(255) │ NOT NULL, UNIQUE │
│ RowVersion │ ROWVERSION │ Concurrency control │
└──────────────┴────────────────┴─────────────────────────────────┘
```
---
## 2. Script DDL
```sql
-- Crear base de datos
CREATE DATABASE StudentEnrollment;
GO
USE StudentEnrollment;
GO
-- Tabla: Professors
CREATE TABLE Professors (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
-- Tabla: Subjects
CREATE TABLE Subjects (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Credits INT NOT NULL DEFAULT 3 CHECK (Credits = 3),
ProfessorId INT NOT NULL,
CONSTRAINT FK_Subjects_Professors
FOREIGN KEY (ProfessorId) REFERENCES Professors(Id)
);
-- Tabla: Students
CREATE TABLE Students (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(255) NOT NULL,
RowVersion ROWVERSION,
CONSTRAINT UQ_Students_Email UNIQUE (Email)
);
-- Tabla: Enrollments
CREATE TABLE Enrollments (
Id INT IDENTITY(1,1) PRIMARY KEY,
StudentId INT NOT NULL,
SubjectId INT NOT NULL,
EnrolledAt DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
CONSTRAINT FK_Enrollments_Students
FOREIGN KEY (StudentId) REFERENCES Students(Id) ON DELETE CASCADE,
CONSTRAINT FK_Enrollments_Subjects
FOREIGN KEY (SubjectId) REFERENCES Subjects(Id),
CONSTRAINT UQ_Enrollments_Student_Subject
UNIQUE (StudentId, SubjectId)
);
-- Índices
CREATE INDEX IX_Subjects_ProfessorId ON Subjects(ProfessorId);
CREATE INDEX IX_Enrollments_StudentId ON Enrollments(StudentId);
CREATE INDEX IX_Enrollments_SubjectId ON Enrollments(SubjectId);
```
---
## 3. Datos Iniciales (Seed)
```sql
-- 5 Profesores
INSERT INTO Professors (Name) VALUES
('Dr. García'), -- Id: 1
('Dra. Martínez'), -- Id: 2
('Dr. López'), -- Id: 3
('Dra. Rodríguez'), -- Id: 4
('Dr. Hernández'); -- Id: 5
-- 10 Materias (2 por profesor)
INSERT INTO Subjects (Name, Credits, ProfessorId) VALUES
('Matemáticas I', 3, 1),
('Matemáticas II', 3, 1),
('Física I', 3, 2),
('Física II', 3, 2),
('Programación I', 3, 3),
('Programación II', 3, 3),
('Base de Datos I', 3, 4),
('Base de Datos II', 3, 4),
('Redes I', 3, 5),
('Redes II', 3, 5);
```
---
## 4. Constraints de Negocio
| Constraint | Tipo | Descripción |
|------------|------|-------------|
| `UQ_Students_Email` | UNIQUE | Email único por estudiante |
| `UQ_Enrollments_Student_Subject` | UNIQUE | No duplicar inscripción |
| `CHECK (Credits = 3)` | CHECK | Créditos siempre = 3 |
| `ON DELETE CASCADE` | FK | Eliminar inscripciones al eliminar estudiante |
---
## 5. Vistas Útiles
```sql
-- Vista: Compañeros de clase
CREATE VIEW vw_Classmates AS
SELECT
e1.StudentId,
s.Name AS SubjectName,
st.Name AS ClassmateName
FROM Enrollments e1
INNER JOIN Enrollments e2 ON e1.SubjectId = e2.SubjectId
AND e1.StudentId != e2.StudentId
INNER JOIN Subjects s ON e1.SubjectId = s.Id
INNER JOIN Students st ON e2.StudentId = st.Id;
-- Vista: Materias disponibles por estudiante
CREATE VIEW vw_AvailableSubjects AS
SELECT
st.Id AS StudentId,
su.Id AS SubjectId,
su.Name AS SubjectName,
p.Name AS ProfessorName,
CASE
WHEN e.Id IS NOT NULL THEN 0 -- Ya inscrito
WHEN ep.ProfessorId IS NOT NULL THEN 0 -- Mismo profesor
ELSE 1
END AS IsAvailable
FROM Students st
CROSS JOIN Subjects su
INNER JOIN Professors p ON su.ProfessorId = p.Id
LEFT JOIN Enrollments e ON st.Id = e.StudentId AND su.Id = e.SubjectId
LEFT JOIN (
SELECT DISTINCT e.StudentId, s.ProfessorId
FROM Enrollments e
INNER JOIN Subjects s ON e.SubjectId = s.Id
) ep ON st.Id = ep.StudentId AND su.ProfessorId = ep.ProfessorId;
```
---
## 6. Diccionario de Datos
| Tabla | Campo | Tipo | Descripción |
|-------|-------|------|-------------|
| Students | Id | INT | Identificador único |
| Students | Name | NVARCHAR(100) | Nombre completo |
| Students | Email | NVARCHAR(255) | Correo (único) |
| Students | RowVersion | ROWVERSION | Control de concurrencia |
| Subjects | Credits | INT | Siempre 3 |
| Enrollments | EnrolledAt | DATETIME2 | Fecha de inscripción UTC |