2009-04-08 15 views
5

Sto creando un Access DB da utilizzare in un'applicazione C# a scuola. Non ho avuto molta esperienza di lavoro con DB, quindi se questo sembra stupido, ignoralo. Voglio che l'utente sia in grado di selezionare tutte le classi che un certo studente ha avuto nel nostro reparto IT. Abbiamo circa 30 in tutto e il massimo che una persona può prendere in 4 anni di scuola superiore è di 15. In questo momento il mio DB ha 15 colonne diverse per ogni classe che un utente potrebbe avere. Come posso comprimerlo in una colonna (se esiste un modo)?Come sbarazzarsi di più colonne in un database?

risposta

18

Ottima domanda Lucas, e questo approfondisce l'atto di normalizzazione del database.

Il fatto che tu abbia riconosciuto il motivo per cui avere più colonne per rappresentare le classi è già sbagliato mostra che hai un grande potenziale.

E se volessimo aggiungere una nuova classe? Ora dobbiamo aggiungere una colonna completamente nuova. C'è poca flessibilità per questo.

Quindi cosa si può fare?

Creiamo TRE tabelle.

Una tabella è per gli studenti:

Student 
    |-------------------------| 
    | StudentID | Student_Name| 
    |-------------------------| 
    |  1  |  John | 
    |  2  |  Sally | 
    |  3  |  Stan | 
    --------------------------- 

Una tabella è per le classi:

Class 
    ------------------------ 
    | ClassID | Class_Name| 
    ------------------------ 
    | 1  | Math | 
    | 2  | Physics | 
    ------------------------ 

E, infine, un tavolo detiene il rapporto tra studenti e classi:

Student_Class 
    ----------------------- 
    | StudentID | ClassID | 
    ----------------------- 

Se volessimo iscrivere John in Physics, inseriremmo una riga nella tabella Student_Class.

INSERT INTO Student_Class (StudentID, ClassID) VALUES (1, 2); 

Ora, abbiamo un record dicendo che Student # 1 (John) frequenta Class # 2 (Fisica). Consente a Sally di frequentare la matematica e Stan frequenta fisica e matematica.

INSERT INTO Student_Class (StudentID, ClassID) VALUES (2, 1); 
    INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 1); 
    INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 2); 

Per tirare i dati di nuovo in modo leggibile, ci uniamo i tre tavoli insieme:

SELECT Student.Student_Name, 
     Class.Class_Name 
    FROM Student, 
     Class, 
     Student_Class 
    WHERE Student.StudentID = Student_Class.StudentID 
     AND Class.ClassID = Student_Class.ClassID; 

Questo ci darebbe un set di risultati come questo:

------------------------------ 
    | Student_Name | Class_Name | 
    ------------------------------ 
    | John  | Physics | 
    | Sally  | Math  | 
    | Stan  | Physics | 
    | Stan  | Math  | 
    ------------------------------ 

E questo è il modo in cui la normalizzazione del database funziona in poche parole.

+0

Ottima risposta. In aggiunta alle informazioni (preziose, corrette) fornite aggiungerei che è possibile memorizzare ulteriori dati sulle classi prese. Se il DB è utile per l'Org, verrà migliorato negli anni successivi. Questo design lo consente. È possibile aggiungere anno classe, tutor, risultato, ecc. – Karl

+0

Grazie per il complimento, ma sinceramente non potevo sopportare di scorrere orizzontalmente attraverso 15 classi. La tua risposta mi è stata di grande aiuto e ora ho iniziato a leggere sulla normalità.Penso che con l'aiuto del tuo design sarò in grado di creare un'app decente per il mio insegnante (lo userà davvero). – Kredns

1

Non ci sono colonne di classe nella tabella degli studenti. Imposta una nuova tabella con id studente e colonne id di classe. Ogni riga rappresenta una classe che lo studente ha preso. Magari aggiungi più colonne come: anno/semestre, voto, ecc.

+0

si può spiegare questo un po 'di più, non esattamente seguo. – Kredns

4

Sembra che tu debba pensare allo schema del tuo database allo normalizing.

C'è uno many-to-many relationship tra studenti e classi in modo tale che molti studenti possono prendere molte classi e molte classi possono essere prese da molti studenti. L'approccio più comune alla gestione di questo scenario è l'utilizzo di junction table.

Qualcosa di simile

Student Table 
------------- 
id 
first_name 
last_name 
dob 

Class Table 
----------- 
id 
class_name 
academic_year 

Student_Class Table 
------------------- 
student_id 
class_id 
year_taken 

Poi le vostre domande sarebbero uniti sui tavoli, per esempio,

SELECT 
    s.last_name + ', ' + s.first_name AS student_name, 
    c.class_name, 
    sc.year_taken 
FROM 
    student s 
INNER JOIN 
    student_class sc 
ON 
    s.id = sc.student_id 
INNER JOIN 
    class c 
ON 
    sc.class_id = class.id 
ORDER BY 
    s.last_name, sc.year_taken 

Una parola di consiglio che vorrei menzionare è che Access richiede di utilizzare le parentesi quando unendo più di una tabella in una query, credo sia perché richiede di specificare un ordine in cui unirsi a loro. Personalmente, trovo questo imbarazzante, in particolare quando sono abituato a scrivere un sacco di SQL senza designer. All'interno di Access, consiglierei di usare il designer per unire le tabelle, quindi modificare l'SQL generato per i tuoi scopi.

4

Quindi hai 15 colonne (ad esempio class1, class2, class3 ... class15)?

Sembra che tu abbia un classico many-to-many relationship. Dovresti creare una nuova tabella per mettere in relazione studenti e classi.

student { StudentID, StudentName ... } 
classes { ClassID, ClassName ... } 
student_classes { StudentID, ClassID } 

Se si sta seguendo lezioni su una base di anno in anno, si potrebbe aggiungere una colonna anno alla relazione così:

student_classes { StudentID, Year, ClassID } 
2

Questo è un problema di normalizzazione. In effetti stai facendo la domanda sbagliata. Invece, poniti la domanda come puoi memorizzare 0 o più classi_taken? Quali altri dettagli hai bisogno di memorizzare su ogni lezione presa? Per esempio. solo la lezione, oi dati presi, il risultato, ecc.?

Ad esempio si consideri qualcosa come il seguente

 
table Student 
id int 
name varchar(25) 
... 

table classes 
id int 
name varchar(25) 
... 

table clases_taken 
student_id int (foreign key to student.id) 
class_id int (foreign key to class.id) 
data_started datatime 
result varchar(5) 
tutor_id int (foreign key to tutor.id) 
... 

2

Non si dovrebbe mai avere colonne come class1, class2, Class3, class4 ecc in una tabella del database. Quello che dovresti avere è una tabella correlata. Il tuo stucture sarebbe qualcosa di simile:

Student Table with the following columns 
StudentID 
StudentLastName 
StudentFirstName 
(and so forth for all the data to describe a student) 

Poi

Course table with the following columns 
CourseId 
CourseName 

Poi

StudentCourse Table with the following columns 
StudentId 
CourseID 
CourseDate 

adesso per scoprire quali corsi la persona ha preso si uniscono queste tabelle insieme. Qualcosa di simile:

Select StudentID,StudentLastName,StudentFirstName, CourseName, CourseDate 
from Student 
join StudentCourse on student. studentid = StudentCourse.StudentID 
join Course on Course.courseID = StudentCourse.CourseID 

Si prega di leggere questo link per iniziare ad imparare i fondamentali del database: http://www.deeptraining.com/litwin/dbdesign/FundamentalsOfRelationalDatabaseDesign.aspx

+0

I aqree ... lancia il flag se hai mai più di una colonna che punta allo stesso FK * e * quella colonna ha un numero che segue il nome. – dotjoe