Mysql
 sql >> Database >  >> RDS >> Mysql

Come memorizzare più opzioni in una singola tabella?

Si prega di leggere su Normalizzazione dei dati , Indicizzazione generale concetti e Chiave esterna vincoli per mantenere i dati puliti con integrità referenziale. Questo ti farà andare avanti.

La memorizzazione dei dati negli array può sembrarti naturale sulla carta, ma per il motore db le prestazioni sono per lo più senza l'uso dell'indice. Inoltre, il giorno 2 scoprirai che raggiungere e mantenere i tuoi dati sarà un incubo.

Quanto segue dovrebbe farti iniziare bene mentre armeggi. Partecipa anche.

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

Crea dati di prova

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

Alcune semplici domande.

Quale corso è in quale dipartimento?

mostra tutto, utilizza alias di tabella (abbreviazioni) per ridurre la digitazione e migliorare la leggibilità (a volte)

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     |
+----------+-----------------------+--------+----------+

Chi parteciperà al corso di World of Chaucer in questo trimestre?

(conoscendo il corsoId=5)

Quanto segue beneficia di uno dei nostri indici compositi in SCJunction. Un composto è un indice su più di una colonna.

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 è iscritto a quale termine è?

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 è sopraffatto, quindi lascia cadere la lezione di matematica

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

esegui quella sopra istruzione select che mostra cosa sta prendendo Kim:

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

Ah, termine molto più semplice. Papà non sarà felice però.

Nota cose come SCJunction.term. Si può scrivere molto su questo, al momento lo salterò principalmente, a parte il dire che dovrebbe essere anche in un FK da qualche parte. Potresti volere che il tuo termine assomigli più a SPRING2015 e non a un int.

E per quanto riguarda id. Questo è il modo in cui lo farei. È preferenza personale. Sarebbe necessario conoscere gli ID #, cercarli. Altri potrebbero scegliere di avere un corsoId qualcosa come HIST101 e non 17. Quelli sono molto più leggibili (ma più lenti nell'indice (a malapena). Quindi fai ciò che è meglio per te.

Indice composito delle note

Un indice composito (INDEX significa CHIAVE e viceversa) è un indice che combina più colonne per un rapido recupero dei dati. Gli ordini vengono capovolti per i due compositi nella tabella SCJunction in modo che, a seconda dell'universo di query che seguono i tuoi dati, il motore db può scegliere quale indice utilizzare per il recupero più rapido in base alla colonna più a sinistra che stai cercando .

Per quanto riguarda la chiave univoca, n. 1, il commento accanto che afferma di non applicare duplicati (che significa dati spazzatura) è piuttosto autoesplicativo. Ad esempio, lo studente 1 corso 1 termine 1 non può esistere due volte in quella tabella.

Un concetto cruciale da comprendere è il concetto di left-most ordinamento dei nomi delle colonne in un indice.

Per le query successive a studentId solo , quindi la chiave con studentId elencato per primo (left-most ) viene utilizzato. Nelle query successive a courseId solo , quindi la chiave con courseId viene utilizzato il più a sinistra. Nelle query che seguono sia studentId che courseId, il motore db può decidere quale chiave composita utilizzare.

Quando dico "segui", intendo nella on clause o where clause condizione.

Se uno non avesse queste due chiavi composte (con la colonna 1 e 2 al loro interno capovolte), nelle query in cui la colonna cercata non è left-most indicizzato, non trarresti vantaggio dall'utilizzo della chiave e subiresti una scansione lenta delle tabelle per la restituzione dei dati.

Quindi, questi due indici combinano i seguenti 2 concetti

  • Recupero rapido dei dati basato sull'estrema sinistra o su entrambi (colonne studentId e courseId)
  • Imporre la non duplicazione dei dati in quella tabella in base ai valori studentId, courseId e termine

Il cibo da asporto

L'importante da asporto è che le tabelle di giunzione consentono un rapido recupero dell'indice e una sana gestione dei dati rispetto ai dati delimitati da virgole (mentalità degli array) stipati in una colonna e tutta la miseria dell'utilizzo di un tale costrutto.