Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment stocker plusieurs options dans une seule table ?

Veuillez lire sur Normalisation des données , Indexation générale concepts et clé étrangère contraintes pour garder les données propres avec intégrité référentielle. Cela vous aidera à démarrer.

Le stockage de données dans des tableaux peut vous sembler naturel sur le papier, mais pour le moteur de base de données, les performances sont généralement sans utilisation d'index. De plus, vous découvrirez le jour 2 que l'accès et la maintenance de vos données seront un cauchemar.

Ce qui suit devrait vous permettre de démarrer du bon pied pendant que vous bricolez. Joins aussi.

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)
);

Créer des données de test

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

Quelques questions simples.

Quel cours est dans quel département ?

afficher tout, utilise des alias de table (abréviations) pour réduire la saisie et améliorer (parfois) la lisibilité

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 suit le cours World of Chaucer ce trimestre ?

(connaître le courseId=5)

Le ci-dessous bénéficie de l'un de nos indices composites dans SCJunction. Un composé est un index sur plusieurs colonnes.

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 inscrite à quoi ce trimestre ?

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 débordée, alors laisse tomber le cours de maths

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

exécutez la déclaration de sélection ci-dessus indiquant ce que Kim prend :

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

Ah, terme beaucoup plus facile. Mais papa ne sera pas content.

Notez des éléments tels que SCJunction.term. Beaucoup de choses peuvent être écrites à ce sujet, je vais le sauter pour le moment, sauf pour dire que cela devrait également être dans un FK quelque part. Vous voudrez peut-être que votre terme ressemble plus à SPRING2015 et non à un int.

Et aussi loin que ça va. C'est ainsi que je procéderais. C'est une préférence personnelle. Cela nécessiterait de connaître les numéros d'identification, de les rechercher. D'autres pourraient choisir d'avoir un courseId quelque chose comme HIST101 et non 17. Ceux-ci sont beaucoup plus lisibles (mais plus lents dans l'index (à peine). Alors faites ce qui est le mieux pour vous.

Notez l'indice composé

Un index composite (INDEX signifie KEY, et vice-versa) est un index qui combine plusieurs colonnes pour une récupération rapide des données. Les ordres sont inversés pour les deux composites dans la table SCJunction afin que, selon l'univers des requêtes qui suivent vos données, le moteur de base de données puisse choisir l'index à utiliser pour une récupération plus rapide en fonction de la colonne la plus à gauche que vous recherchez. .

En ce qui concerne la clé unique, n ° 1, le commentaire à côté indiquant qu'il n'y a pas de doublons (c'est-à-dire des données indésirables) est plutôt explicite. Par exemple, étudiant 1 cours 1 trimestre 1 ne peut pas exister deux fois dans ce tableau.

Un concept crucial à comprendre est le concept de left-most ordre des noms de colonnes dans un index.

Pour les requêtes qui vont après studentId uniquement , puis la clé qui a studentId répertorié en premier (left-most ) est utilisé. Dans les requêtes qui vont après courseId uniquement , puis la clé qui a courseId le plus à gauche est utilisé. Dans les requêtes qui suivent à la fois studentId et courseId, le moteur de base de données peut décider quelle clé composite utiliser.

Quand je dis "aller après", je veux dire dans la clause on clause ou where clause état.

Si l'on n'avait pas ces deux clés composites (avec les colonnes 1 et 2 inversées), alors dans les requêtes où la colonne recherchée n'est pas left-most indexé, vous ne bénéficieriez pas de l'utilisation de la clé et souffririez d'un balayage lent de la table pour que les données soient renvoyées.

Ainsi, ces deux index combinent les 2 concepts suivants

  • Récupération rapide des données basée sur les colonnes les plus à gauche ou les deux (colonnes studentId et courseId)
  • Imposer la non-duplication des données dans cette table en fonction des valeurs studentId, courseId et term

Les plats à emporter

L'important plat à emporter est que les tables de jonction permettent une récupération rapide des index et une gestion saine des données par rapport aux données délimitées par des virgules (état d'esprit des tableaux) entassées dans une colonne, et toute la misère d'utiliser une telle construction.