Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como armazenar várias opções em uma única tabela?


Leia sobre Normalização de dados , Indexação geral conceitos e Chave estrangeira restrições para manter os dados limpos com integridade referencial. Isso vai fazer você ir.

Armazenar dados em arrays pode parecer natural para você no papel, mas para o mecanismo de banco de dados o desempenho geralmente é sem uso de índice. Além disso, você descobrirá no dia 2 que obter e manter seus dados será um pesadelo.

O seguinte deve ajudá-lo a começar bem enquanto você mexe. Participações também.
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)
);

Criar dados de teste

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

Algumas perguntas simples.

Qual ​​é o curso em qual departamento?


mostrar tudo, usa aliases de tabela (abreviações) para tornar a digitação menos, legibilidade (às vezes) melhor
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     |
+----------+-----------------------+--------+----------+

Quem está fazendo o curso World of Chaucer neste semestre?


(conhecendo o courseId=5)

O abaixo se beneficia de um de nossos índices compostos no SCJunction. Um composto é um índice em mais de uma coluna.
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 está inscrita neste período?

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 está sobrecarregada, então largue a aula de matemática
delete from SCJunction
where studentId=2 and courseId=4 and term=100

execute a instrução select acima mostrando o que Kim está tomando:
+-----------+--------------+----------+--------------------+
| StudentId | FullName     | courseId | courseName         |
+-----------+--------------+----------+--------------------+
|         2 | Kim Billings |        5 | World of Chaucer   |
|         2 | Kim Billings |        1 | Early Roman Empire |
+-----------+--------------+----------+--------------------+

Ah, termo muito mais fácil. Mas papai não vai ficar feliz.

Observe coisas como SCJunction.term. Muito pode ser escrito sobre isso, vou pular sobre isso no momento principalmente, além de dizer que também deve estar em um FK em algum lugar. Você pode querer que seu termo se pareça mais com SPRING2015 e não com um int.

E até onde eu vou. Esta é a maneira que eu faria. É preferência pessoal. Seria necessário conhecer os id #'s, procurá-los. Outros podem optar por ter um courseId algo como HIST101 e não 17. Esses são altamente mais legíveis (mas mais lentos no índice (pouco). Então faça o que for melhor para você.

Índice Composto de Notas


Um Índice Composto (INDEX significa KEY e vice-versa) é aquele que combina várias colunas para recuperação rápida de dados. As ordens são invertidas para os dois compostos na tabela SCJunction para que, dependendo do universo de consultas que seguem seus dados, o mecanismo de banco de dados possa escolher qual índice usar para recuperação mais rápida com base na coluna mais à esquerda que você está procurando .

Quanto à chave exclusiva, nº 1, o comentário ao lado dela afirmando que não há duplicatas (ou seja, dados inúteis) é bastante autoexplicativo. Por exemplo, aluno 1 curso 1 período 1 não pode existir duas vezes nessa tabela.

Um conceito crucial para entender é o conceito de left-most ordenação dos nomes das colunas em um índice.

Para consultas que seguem studentId somente , então a chave que tem studentId listado primeiro (left-most ) é usado. Em consultas que seguem courseId somente , então a chave que tem courseId mais à esquerda é usado. Em consultas que vão depois de studentId e courseId, o mecanismo de banco de dados pode decidir qual chave composta usar.

Quando digo "ir atrás", quero dizer na cláusula on clause ou where clause doença.

Se não houvesse essas duas chaves compostas (com as colunas 1 e 2 invertidas), nas consultas em que a coluna procurada não é left-most indexado, você não se beneficiaria com o uso da chave e sofreria uma varredura de tabelas lenta para que os dados retornassem.

Então, esses dois índices combinam os 2 conceitos a seguir
  • Recuperação rápida de dados com base na extremidade esquerda ou em ambas (colunas studentId e courseId)
  • Aplicar a não duplicação de dados nessa tabela com base nos valores de studentId, courseId e term

A lição


O importante lembrança é que as tabelas de junção facilitam a recuperação rápida do índice e o gerenciamento sensato de dados versus dados delimitados por vírgulas (mentalidade de matriz) amontoados em uma coluna e toda a miséria de usar essa construção.