sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo almacenar múltiples opciones en una sola tabla?

Lea sobre Normalización de datos , Indización general conceptos y Foreign Key Restricciones para mantener los datos limpios con integridad referencial. Esto te pondrá en marcha.

El almacenamiento de datos en matrices puede parecer natural para usted en papel, pero para el motor de base de datos, el rendimiento será mayormente sin uso de índice. Además, el día 2 descubrirá que acceder a sus datos y mantenerlos será una pesadilla.

Lo siguiente debería ponerlo en marcha con un buen comienzo mientras juega. Únete también.

create table student
(   studentId int auto_increment primary key,
    fullName varchar(100) not null
    -- etc
);

create table dept
(   deptId int auto_increment primary key,
    deptName varchar(100) not null -- Economics
    -- etc
);

create table course
(   courseId int auto_increment primary key,
    deptId int not null,
    courseName varchar(100) not null,
    -- etc
    CONSTRAINT fk_crs_dept FOREIGN KEY (deptId) REFERENCES dept(deptId)
);

create table SCJunction
(   -- Student/Course Junction table (a.k.a Student is taking the course)
    -- also holds the attendance and grade
    id int auto_increment primary key,
    studentId int not null,
    courseId int not null,
    term int not null, -- term (I am using 100 in below examples for this term)
    attendance int not null, -- whatever you want, 100=always there, 0=he must have been partying,
    grade int not null, -- just an idea   
    -- See (Note Composite Index) at bottom concerning next two lines.
    unique key(studentId,courseId,term), -- no duplicates allowed for the combo (note student can re-take it next term)
    key (courseId,studentId),
    CONSTRAINT fk_sc_student FOREIGN KEY (studentId) REFERENCES student(studentId),
    CONSTRAINT fk_sc_courses FOREIGN KEY (courseId) REFERENCES course(courseId)
);

Crear datos de prueba

insert student(fullName) values ('Henry Carthage'),('Kim Billings'),('Shy Guy'); -- id's 1,2,3
insert student(fullName) values ('Shy Guy');

insert dept(deptName) values ('History'),('Math'),('English'); -- id's 1,2,3

insert course(deptId,courseName) values (1,'Early Roman Empire'),(1,'Italian Nation States'); -- id's 1 and 2 (History dept)
insert course(deptId,courseName) values (2,'Calculus 1'),(2,'Linear Algebra A'); -- id's 3 and 4 (Math dept)
insert course(deptId,courseName) values (3,'World of Chaucer'); -- id 5 (English dept)

-- show why FK constraints are important based on data at the moment
insert course(deptId,courseName) values (66,'Fly Fishing 101'); -- will generate error 1452. That dept 66 does not exist
-- That error is a good error to have. Better than faulty data

-- Have Kim (studentId=2) enrolled in a few courses
insert SCJunction(studentId,courseId,term,attendance,grade) values (2,1,100,-1,-1); -- Early Roman Empire, term 100 (made up), unknown attendance/grade
insert SCJunction(studentId,courseId,term,attendance,grade) values (2,4,100,-1,-1); -- Linear Algebra A
insert SCJunction(studentId,courseId,term,attendance,grade) values (2,5,100,-1,-1); -- World of Chaucer

-- Have Shy Guy (studentId=3) enrolled in one course only. He is shy
insert SCJunction(studentId,courseId,term,attendance,grade) values (3,5,100,-1,-1); -- Early Roman Empire, term 100 (made up), unknow attendance/grade
-- note if you run that line again, the Error 1062 Duplicate entry happens. Can't take same course more than once per term

Algunas preguntas simples.

¿Qué curso es en qué departamento?

mostrar todo, utiliza alias de tablas (abreviaturas) para que se escriba menos y la legibilidad (a veces) sea mejor

select c.courseId,c.courseName,d.deptId,d.deptName
from course c
join dept d
on c.deptId=d.deptId
order by d.deptName,c.courseName -- note the order
+----------+-----------------------+--------+----------+
| courseId | courseName            | deptId | deptName |
+----------+-----------------------+--------+----------+
|        5 | World of Chaucer      |      3 | English  |
|        1 | Early Roman Empire    |      1 | History  |
|        2 | Italian Nation States |      1 | History  |
|        3 | Calculus 1            |      2 | Math     |
|        4 | Linear Algebra A      |      2 | Math     |
+----------+-----------------------+--------+----------+

¿Quién está tomando el curso World of Chaucer este trimestre?

(conociendo el IdCurso=5)

Los siguientes se benefician de uno de nuestros índices compuestos en SCJunction. Un compuesto es un índice en más de una columna.

select s.StudentId,s.FullName
from SCJunction j
join student s
on j.studentId=s.studentId
where j.courseId=5 and j.term=100
+-----------+--------------+
| StudentId | FullName     |
+-----------+--------------+
|         2 | Kim Billings |
|         3 | Shy Guy      |
+-----------+--------------+

¿Kim Billings está inscrita en qué término?

select s.StudentId,s.FullName,c.courseId,c.courseName
from SCJunction j
join student s
on j.studentId=s.studentId
join course c
on j.courseId=c.courseId
where s.studentId=2 and j.term=100
order by c.courseId DESC -- descending, just for the fun of it
+-----------+--------------+----------+--------------------+
| StudentId | FullName     | courseId | courseName         |
+-----------+--------------+----------+--------------------+
|         2 | Kim Billings |        5 | World of Chaucer   |
|         2 | Kim Billings |        4 | Linear Algebra A   |
|         2 | Kim Billings |        1 | Early Roman Empire |
+-----------+--------------+----------+--------------------+

Kim está abrumada, así que deja la clase de matemáticas

delete from SCJunction
where studentId=2 and courseId=4 and term=100

ejecute la declaración de selección anterior que muestra lo que Kim está tomando:

+-----------+--------------+----------+--------------------+
| StudentId | FullName     | courseId | courseName         |
+-----------+--------------+----------+--------------------+
|         2 | Kim Billings |        5 | World of Chaucer   |
|         2 | Kim Billings |        1 | Early Roman Empire |
+-----------+--------------+----------+--------------------+

Ah, término mucho más fácil. Sin embargo, papá no estará feliz.

Tenga en cuenta cosas como SCJunction.term. Se puede escribir mucho sobre eso, lo pasaré por alto en este momento, aparte de decir que también debería estar en un FK en alguna parte. Es posible que desee que su término se parezca más a PRIMAVERA2015 y no a un entero.

Y en lo que respecta a la identificación. Esta es la forma en que lo haría. Es preferencia personal. Requeriría conocer los números de identificación, buscarlos. Otros podrían optar por tener un ID de curso como HIST101 y no 17. Esos son mucho más legibles (pero más lentos en el índice (apenas). Así que haz lo que sea mejor para ti.

Índice compuesto de notas

Un índice compuesto (ÍNDICE significa CLAVE y viceversa) es uno que combina múltiples columnas para una rápida recuperación de datos. Los órdenes se invierten para los dos compuestos en la tabla SCJunction de modo que, según el universo de consultas que persiguen sus datos, el motor de base de datos puede elegir qué índice usar para una recuperación más rápida en función de la columna más a la izquierda que busca. .

En cuanto a la clave única, n.º 1, el comentario junto a ella que indica que no se aplican duplicados (es decir, datos basura) se explica por sí mismo. Por ejemplo, estudiante 1 curso 1 trimestre 1 no puede existir dos veces en esa tabla.

Un concepto crucial para entender es el concepto de left-most ordenación de nombres de columnas en un índice.

Para consultas que van después de studentId solo , luego la clave que tiene studentId aparece primero (left-most ) se utiliza. En consultas que van después de courseId solo , luego la clave que tiene courseId se utiliza el extremo izquierdo. En las consultas que van después de StudentId y CourseId, el motor de base de datos puede decidir qué clave compuesta usar.

Cuando digo "ir tras", me refiero a la cláusula on clause o where clause condición.

Si uno no tuviera esas dos claves compuestas (con las columnas 1 y 2 invertidas), entonces en las consultas donde la columna buscada no está left-most indexado, no se beneficiaría con el uso de claves y sufriría un escaneo de tablas lento para que los datos regresen.

Entonces, esos dos índices combinan los siguientes 2 conceptos

  • Recuperación rápida de datos basada en el extremo izquierdo o en ambos (columnas de ID de estudiante y de ID de curso)
  • Hacer cumplir la no duplicación de datos en esa tabla en función de los valores de ID de estudiante, ID de curso y término

La comida para llevar

La conclusión importante es que las tablas de unión permiten una recuperación rápida del índice y una gestión sensata de los datos frente a los datos delimitados por comas (mentalidad de matriz) abarrotados en una columna, y toda la miseria de usar una construcción de este tipo.