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

Hvordan gemmer man flere muligheder i en enkelt tabel?

Læs venligst om Datanormalisering , Generel indeksering koncepter og fremmednøgle begrænsninger for at holde data rene med referentiel integritet. Dette får dig i gang.

Lagring af data i arrays kan virke naturligt for dig på papiret, men for db-motoren er ydeevnen for det meste uden indeksbrug. Desuden vil du opdage på dag 2, at det vil være et mareridt at komme til og vedligeholde dine data.

Følgende bør få dig i gang med en god start, mens du piller. Deltager også.

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

Opret testdata

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
 

Nogle enkle spørgsmål.

Hvilket kursus er i hvilken afdeling?

vis alle, bruger tabelaliasser (forkortelser) for at gøre skrivning mindre, læsbarheden (nogle gange) bedre

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

Hvem tager World of Chaucer-kurset i denne periode?

(ved at kende kursusId=5)

Nedenstående drager fordel af et af vores sammensatte indekser i SCJunction. En sammensat er et indeks på mere end én kolonne.

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

Hvad er Kim Billings tilmeldt denne periode?

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 er overvældet, så drop matematiktimen

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

kør ovenstående udvalgte erklæring, der viser, hvad Kim tager:

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

Ah, meget lettere udtryk. Far vil dog ikke være glad.

Bemærk sådanne ting som SCJunction.term. Der kan skrives meget om det, det vil jeg springe over i øjeblikket for det meste, andet end at sige at det også burde være i et FK et eller andet sted. Du vil måske have, at din periode ligner FORÅR2015 og ikke en int.

Og hvad angår id. Det er den måde, jeg ville gøre det på. Det er personlig præference. Det ville kræve at kende id #'er og slå dem op. Andre kunne vælge at have et kursus-id noget som HIST101 og ikke 17. De er meget mere læsbare (men langsommere i indekset (næppe). Så gør, hvad der er bedst for dig.

Note Composite Index

Et sammensat indeks (INDEX betyder NØGLE og omvendt) er et, der kombinerer flere kolonner for hurtig datahentning. Ordrerne vendes for de to sammensætninger i SCJunction-tabellen, så afhængigt af universet af forespørgsler, der går efter dine data, kan db-motoren vælge hvilket indeks, der skal bruges til hurtigst hentning baseret på kolonnen længst til venstre, du går efter .

Med hensyn til den unikke nøgle, #1, er kommentaren ved siden af ​​den, hvori der står at håndhæve ingen dubletter (hvilket betyder uønsket data), temmelig selvforklarende. For eksempel kan elev 1 kursus 1 semester 1 ikke eksistere to gange i den tabel.

Et afgørende koncept at forstå er konceptet left-most rækkefølge af kolonnenavne i et indeks.

For forespørgsler, der går efter studentId kun , derefter nøglen, der har studentId anført først (left-most ) anvendes. I forespørgsler, der går efter courseId kun , derefter nøglen, der har courseId længst til venstre bruges. I forespørgsler, der går efter både studentId og courseId, kan db-motoren bestemme, hvilken sammensat nøgle der skal bruges.

Når jeg siger "gå efter", mener jeg i on clause eller where clause tilstand.

Hvis man ikke skulle have disse to sammensatte nøgler (med kolonne 1 og 2 i dem vendt), så i forespørgsler, hvor den søgte kolonne ikke er left-most indekseret, ville du ikke have gavn af nøglebrug og lide under en langsom tabelscanning for data at returnere.

Så disse to indekser kombinerer de følgende 2 begreber

  • Hurtig datahentning baseret på længst til venstre eller begge (studentId og courseId kolonner)
  • Håndhævelse af ikke-duplikering af data i den tabel baseret på elev-id, kursus-id og termværdier

The Takeaway

Den vigtige takeaway er, at Junction-tabeller giver mulighed for hurtig indekshentning og fornuftig styring af data versus kommaafgrænsede data (array-tankegang) proppet ind i en kolonne, og al den elendighed ved at bruge sådan en konstruktion.



  1. Hvor er mit ugyldige tegn (ORA-00911)

  2. 3 måder at liste alle funktioner i PostgreSQL

  3. java - passerer array i oracle-lagret procedure

  4. Serialisering af sletninger fra Clustered Columnstore-indekser