Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak przechowywać wiele opcji w jednej tabeli?

Przeczytaj o normalizacji danych , Indeksowanie ogólne koncepcje i klucz obcy ograniczenia zapewniające czystość danych i integralność referencyjną. To cię pobudzi.

Przechowywanie danych w tablicach może wydawać się naturalne na papierze, ale dla silnika bazy danych wydajność jest w większości przypadków bez użycia indeksu. Co więcej, w dniu 2 przekonasz się, że uzyskanie i utrzymanie danych będzie koszmarem.

Poniższe informacje powinny zapewnić Ci dobry początek podczas majsterkowania. Dołączenia też.

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

Utwórz dane testowe

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

Kilka prostych pytań.

Jaki kurs jest w jakim dziale?

pokaż wszystko, używa aliasów tabel (skrótów), aby pisać mniej, czytelność (czasami) lepsza

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

Kto uczęszcza na kurs World of Chaucer w tym semestrze?

(znając CourseId=5)

Poniższe korzysta z jednego z naszych indeksów złożonych w SCJunction. Złożony jest indeksem w więcej niż jednej kolumnie.

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 jest zapisany w jakim okresie?

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 jest przytłoczona, więc porzuć lekcję matematyki

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

uruchom powyższe zdanie select pokazujące, co robi Kim:

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

Ach, znacznie łatwiejszy termin. Tata nie będzie jednak szczęśliwy.

Zwróć uwagę na takie rzeczy jak SCJunction.term. Dużo można o tym napisać, w tej chwili przeważnie to pominę, poza stwierdzeniem, że też powinno być gdzieś w FK. Możesz chcieć, aby Twoje hasło wyglądało bardziej jak WIOSNA 2015, a nie int.

I jeśli chodzi o to. Tak bym to zrobił. To osobiste preferencje. Wymagałoby to znajomości identyfikatorów i wyszukania ich. Inni mogą wybrać kursId coś w rodzaju HIST101, a nie 17. Są one o wiele bardziej czytelne (ale wolniej w indeksie (ledwo). Więc rób to, co jest dla Ciebie najlepsze.

Uwaga Indeks złożony

Indeks złożony (INDEKS oznacza KLUCZ i na odwrót) to taki, który łączy wiele kolumn w celu szybkiego wyszukiwania danych. Kolejności są odwracane dla dwóch kompozytów w tabeli SCJunction, dzięki czemu, w zależności od zbioru zapytań, które dotyczą danych, silnik bazy danych może wybrać indeks, który ma być używany do najszybszego pobierania, na podstawie skrajnej lewej kolumny, po której następuje .

Jeśli chodzi o unikalny klucz, nr 1, komentarz obok niego stwierdzający, że nie należy wymuszać duplikatów (czyli niepotrzebnych danych) jest raczej oczywisty. Na przykład uczeń 1, kurs 1, semestr 1, nie może występować dwa razy w tej tabeli.

Kluczowym pojęciem do zrozumienia jest pojęcie left-most uporządkowanie nazw kolumn w indeksie.

W przypadku zapytań, które idą po studentId tylko , a następnie klucz, który ma studentId wymienione jako pierwsze (left-most ) Jest używane. W zapytaniach, które idą po courseId tylko , a następnie klucz, który ma courseId używany jest najbardziej lewy. W zapytaniach, które idą po identyfikatorach studentId i courseId, silnik bazy danych może zdecydować, którego klucza złożonego użyć.

Kiedy mówię „idź po”, mam na myśli klauzulę on clause lub where clause stan.

Gdyby nie mieć tych dwóch kluczy złożonych (z odwróconymi kolumnami 1 i 2), to w zapytaniach, w których szukana kolumna nie jest left-most zindeksowane, nie odniesiesz korzyści z użycia klucza i będziesz cierpieć z powodu powolnego skanowania tabel w celu zwrócenia danych.

Tak więc te dwa indeksy łączą następujące dwie koncepcje

  • Szybkie pobieranie danych na podstawie skrajnej lewej strony lub obu (kolumny studentId i courseId)
  • Wymuszanie braku powielania danych w tej tabeli na podstawie wartości studentId, courseId i terminów

Na wynos

Ważny na wynos jest to, że tabele połączeń umożliwiają szybkie wyszukiwanie indeksów i rozsądne zarządzanie danymi w porównaniu z danymi rozdzielanymi przecinkami (nastawienie na tablice) upchniętymi w kolumnie i całą niedolą związaną z używaniem takiej konstrukcji.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Różnica między FIELD() i FIND_IN_SET() w MySQL

  2. Jak przechowywać znak Emoji w bazie danych MySQL

  3. Fałszywe ograniczenie klucza obcego nie działa

  4. Przejdź z tradycyjnej replikacji do GTID

  5. Jak sprawdzić, czy wartość jest liczbą całkowitą w MySQL?