Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie speichert man mehrere Optionen in einer einzigen Tabelle?

Bitte informieren Sie sich über Datennormalisierung , Allgemeine Indizierung Konzepte und Fremdschlüssel Beschränkungen, um Daten mit referenzieller Integrität sauber zu halten. Das bringt Sie weiter.

Das Speichern von Daten in Arrays mag Ihnen auf dem Papier natürlich erscheinen, aber für die db-Engine ist die Leistung meistens ohne Indexverwendung. Darüber hinaus werden Sie am zweiten Tag feststellen, dass es ein Albtraum sein wird, an Ihre Daten zu gelangen und diese zu verwalten.

Das Folgende sollte Ihnen einen guten Start beim Basteln ermöglichen. Beitreten auch.

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

Testdaten erstellen

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

Einige einfache Fragen.

Welcher Studiengang ist in welchem ​​Fachbereich?

alles anzeigen, verwendet Tabellenaliase (Abkürzungen), um das Tippen zu verringern und die Lesbarkeit (manchmal) besser zu machen

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

Wer nimmt dieses Semester am World of Chaucer-Kurs teil?

(in Kenntnis der Kurs-ID=5)

Das Folgende profitiert von einem unserer zusammengesetzten Indizes in SCJunction. Ein zusammengesetzter Index ist ein Index für mehr als eine Spalte.

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 ist in welchem ​​Semester eingeschrieben?

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 ist überwältigt, also lass den Matheunterricht fallen

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

Führen Sie die obige Select-Anweisung aus, die zeigt, was Kim nimmt:

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

Ah, viel einfacher Begriff. Dad wird aber nicht glücklich sein.

Beachten Sie Dinge wie SCJunction.term. Darüber lässt sich viel schreiben, ich überspringe es im Moment meistens, außer zu sagen, es müsste auch irgendwo in einem FK stehen. Möglicherweise möchten Sie, dass Ihr Begriff eher wie SPRING2015 aussieht und nicht wie ein int.

Und soweit es geht. So würde ich es machen. Es ist eine persönliche Präferenz. Es würde erfordern, die ID-Nummern zu kennen und sie nachzuschlagen. Andere könnten sich für eine Kurs-ID wie HIST101 und nicht 17 entscheiden. Diese sind viel besser lesbar (aber langsamer im Index (kaum). Also tun Sie, was für Sie am besten ist.

Zusammengesetzter Index beachten

Ein zusammengesetzter Index (INDEX bedeutet SCHLÜSSEL und umgekehrt) ist ein Index, der mehrere Spalten zum schnellen Abrufen von Daten kombiniert. Die Reihenfolgen werden für die beiden zusammengesetzten Elemente in der SCJunction-Tabelle umgedreht, sodass die DB-Engine je nach Abfrageuniversum, die nach Ihren Daten gehen, auswählen kann, welcher Index für den schnellsten Abruf verwendet werden soll, basierend auf der Spalte ganz links, die Sie suchen .

Was den eindeutigen Schlüssel Nr. 1 betrifft, ist der Kommentar daneben, der besagt, dass keine Duplikate erzwungen werden sollen (was Junk-Daten bedeutet), ziemlich selbsterklärend. Beispiel:Student 1 Kurs 1 Semester 1 darf in dieser Tabelle nicht zweimal vorkommen.

Ein wichtiges Konzept, das Sie verstehen müssen, ist das Konzept von left-most Reihenfolge der Spaltennamen in einem Index.

Für Abfragen, die nach studentId gehen nur , dann den Schlüssel mit studentId zuerst aufgeführt (left-most ) wird genutzt. In Abfragen, die nach courseId gehen nur , dann den Schlüssel mit courseId ganz links wird verwendet. Bei Abfragen, die sowohl nach studentId als auch nach courseId gehen, kann die DB-Engine entscheiden, welcher zusammengesetzte Schlüssel verwendet werden soll.

Wenn ich sage "hinter gehen", meine ich in der on clause oder where clause Zustand.

Hätte man diese beiden zusammengesetzten Schlüssel nicht (mit gespiegelten Spalten 1 und 2), dann in Abfragen, in denen die gesuchte Spalte nicht left-most ist indiziert, würden Sie nicht von der Schlüsselverwendung profitieren und einen langsamen Tablescan für zurückzugebende Daten erleiden.

Diese beiden Indizes kombinieren also die folgenden zwei Konzepte

  • Schneller Datenabruf basierend auf ganz links oder beiden (StudentId- und CourseId-Spalten)
  • Erzwingen der Nichtduplizierung von Daten in dieser Tabelle basierend auf den Werten studentId, courseId und term

Der Imbiss

Das wichtige Mitnehmen ist, dass Junction-Tabellen für einen schnellen Indexabruf und eine vernünftige Verwaltung von Daten im Vergleich zu kommagetrennten Daten (Array-Denkweise) sorgen, die in eine Spalte gestopft sind, und all das Elend, das mit der Verwendung eines solchen Konstrukts verbunden ist.