sql >> Databáze >  >> RDS >> Mysql

Jak uložit více možností do jedné tabulky?

Přečtěte si prosím Normalizace dat , Obecné indexování koncepty a Zahraniční klíč omezení, aby byla data čistá s referenční integritou. Tohle vás rozjede.

Ukládání dat do polí vám může na papíře připadat přirozené, ale pro db engine je výkon většinou bez použití indexu. Navíc 2. den zjistíte, že dostat se k vašim datům a udržovat je bude noční můrou.

Následující text by vám měl při vrtání dobře nastartovat. Připojení taky.

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

Vytvoření testovacích dat

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

Pár jednoduchých otázek.

Jaký kurz je na kterém oddělení?

zobrazit vše, používá aliasy tabulek (zkratky), aby bylo méně psaní, čitelnost (někdy) lepší

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

Kdo v tomto semestru absolvuje kurz World of Chaucer?

(znáte kurzId=5)

Níže uvedené těží z jednoho z našich složených indexů v SCJunction. Složený je index ve více než jednom sloupci.

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

V jakém období je Kim Billings zapsána?

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 je ohromená, tak zahoďte hodinu matematiky

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

spusťte výše uvedený příkaz select ukazující, co Kim bere:

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

Ach, mnohem jednodušší termín. Táta ale nebude šťastný.

Všimněte si věcí jako SCJunction.term. O tom se dá hodně napsat, v tuto chvíli to většinou přeskočím, jinak bych řekl, že by to mělo být i někde v FK. Možná budete chtít, aby váš termín vypadal spíše jako JARO 2015 a ne jako int.

A pokud jde o id. Takhle bych to udělal já. Je to osobní preference. Vyžadovalo by to znát ID #, vyhledávat je. Jiní by se mohli rozhodnout, že budou mít CourseId něco jako HIST101 a ne 17. Ty jsou mnohem čitelnější (ale pomalejší v indexu (sotva). Udělejte tedy to, co je pro vás nejlepší.

Složený index poznámky

Složený index (INDEX znamená KLÍČ a naopak) je index, který kombinuje více sloupců pro rychlé načítání dat. Objednávky jsou převráceny pro dva kompozity v tabulce SCJunction, takže v závislosti na množině dotazů, které jdou po vašich datech, může db engine vybrat, který index použít pro nejrychlejší načtení na základě sloupce zcela vlevo, za kterým se chystáte. .

Pokud jde o jedinečný klíč č. 1, komentář vedle něj, který uvádí, že se nevynucují žádné duplikáty (myšleno nevyžádaná data), je spíše samovysvětlující. Například student 1 kurz 1 semestr 1 nemůže v této tabulce existovat dvakrát.

Klíčovým konceptem, kterému je třeba porozumět, je koncept left-most řazení názvů sloupců v indexu.

Pro dotazy, které následují za studentId pouze a poté klíč, který má studentId uveden jako první (left-most ) se používá. V dotazech, které následují za courseId pouze a poté klíč, který má courseId používá se nejvíce vlevo. V dotazech, které jdou po studentId i courseId, může db engine rozhodnout, který složený klíč použít.

Když říkám "jdi po", myslím v on clause nebo where clause podmínka.

Pokud bychom neměli tyto dva složené klíče (se sloupci 1 a 2 v nich převrácenými), pak v dotazech, kde hledaný sloupec není left-most indexované, nebudete mít prospěch z používání klíče a budete trpět pomalým vyhledáváním dat v tabulce.

Tyto dva indexy tedy kombinují následující 2 koncepty

  • Rychlé načítání dat na základě zcela vlevo nebo obou (sloupce studentId a courseId)
  • Vynucení neduplikace dat v této tabulce na základě hodnot studentId, courseId a term

Stávka s sebou

Důležité s sebou spočívá v tom, že spojovací tabulky umožňují rychlé načítání indexů a rozumnou správu dat oproti datům odděleným čárkou (soubor myšlení) nacpaných do sloupce a všechna ta trápení spojená s používáním takové konstrukce.



  1. DATE_ADD() Příklady – MySQL

  2. Jak POSITION() funguje v MariaDB

  3. Deset způsobů, jak rozšířit funkčnost PostgreSQL

  4. Pochopení typů dat a funkcí PostgreSQL (podle příkladů)