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

W jaki sposób można zaprojektować prostą relacyjną relacyjną bazę danych nauczyciel-przedmiot-uczeń-wsadowy?

Brakuje tabeli kojarzącej przedmioty i uczniów (w punkcie 2):

// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)

Zwróć uwagę, że każda tabela podstawowa ma skojarzony szablon instrukcji dla instrukcji dotyczących sytuacji biznesowej, sparametryzowany przez nazwy kolumn — jego (charakterystyczny) predykat . Do tabeli trafiają wiersze, które sprawiają, że orzeczenie jest prawdziwe. Zauważ, że definicja tabeli wygląda jak skrót predykatu.

// teacher [id] named [name] with email [email] teaches subject [subject_id]
teacher(id, name, email, subject_id)

// subject [id] named [name] is [description]
subject(id, name, description)

// student [id] named [name] lives at [location])
student(id, name, location)

// batch [id] at venue [venue] was taught by teacher [teacher_id] on date [date]
batch(id, venue, teacher_id, date)

// student-batch [id] reports student [student_id] being in batch [batch_id]
student-batch(id, student_id, batch_id)
// CHECK student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

Ponieważ wydajesz się być zakłopotany tym, wyprowadzę to pod kątem tego, w jaki sposób możemy uzasadnić projektowanie tabel, ograniczeń i zapytań. Wydaje się, że jednym ze sposobów wyrażenia żądanego ograniczenia jest skomentowany powyżej CHECK.

Aby wyrazić dowolną tabelę, ograniczenie lub zapytanie w SQL, najpierw decydujemy o jego predykacie. Następnie możemy skonwertować orzeczenie na skrót. Następnie możemy przekonwertować skrót na SQL.

Orzeczenie:

student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

Korzystanie z predykatów tabeli podstawowej:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND student [k.student_id] takes subject [k.subject_id]
AND teacher [t.id] named [t.name] with email [t.email] teaches subject [t.subject_id] 
AND batch [b.id] at venue [b.venue] was taught by teacher [b.teacher_id] on date [b.date]
AND [k.subject_id] = [t.subject_id]
AND [t.id] = [b.teacher_id])

Używanie skrótów:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, date)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id)

W FROM każdy (prawdopodobnie niejawny) alias reprezentuje tabelę taką jak podana nazwa tabeli bazowej i/lub podzapytanie, ale z każdą kolumną w jej wartości i predykacie przemianowanym na alias .kolumna .

Otrzymujemy wiersze spełniające AND dwóch predykatów przez JOINowanie tabel predykatów w SQL. Jeśli chcemy, aby wiersze spełniały warunek AND warunku, używamy ON lub WHERE w SQL.

Klauzula SELECT zwraca wiersze, w których FOR SOME wartości kolumn z kropkami zwrócone (niekropkowane) kolumny są równe funkcjom kolumn z kropkami, które spełniają predykat FROM.

SQL:Zastąp instrukcje ich tabelami AND przez JOIN lub ON lub WHERE, a zewnętrzne FOR SOME &THERE EXISTS przez SELECT:

SELECT t.student_id AS student_id, b.bid AS batch_id
FROM takes k JOIN teacher t JOIN batch b
WHERE k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND student_id = t.student_id
AND batch_id = b.id

Tabela wierszy spełniających OR dwóch predykatów jest UNIĄ ich tabel. Dla AND NOT używamy EXCEPT (aka MINUS) (lub idiomu LEFT JOIN). DLA NIEKTÓRYCH lub ISTNIEJE nad wszystkimi kolumnami nie można odpytywać w SQL, ale jeśli chcemy wiedzieć, czy istnieją wiersze spełniające predykat, możemy użyć opcji ISTNIEJE wokół podzapytania z tym predykatem.

Załóżmy, że chcemy ograniczyć tabelę podstawową tak, aby każdy wiersz spełniał predykat w niektórych kolumnach. Tj. DLA WSZYSTKICH kolumn JEŚLI spełniają one predykat bazowy, TO spełniają predykat zapytania. Tj. DLA WSZYSTKICH kolumn JEŚLI wiersz, który tworzą, znajduje się w bazie, TO jest w zapytaniu. Więc wymagamy w SQL, że NIE ISTNIEJE (SELECT kolumny FROM base EXCEPT query). Lub dla każdego wiersza w bazie wymagamy w SQL, że ISTNIEJE(zapytanie).

W standardowym SQL można CREATE ASSERTION CHECK (NOT EXISTS (SELECT student_id, batch_id FROM student-batch EXCEPT query)) lub w CREATE TABLE student-batch można CHECK (EXISTS (zapytanie)). Niestety nie są one obsługiwane przez MySQL ani większość DBMS. Jeśli wstawisz do partii studentów po partii, możesz wymagać, aby przy wyzwalaniu, że ISTNIEJE (zapytanie). Możesz też dodać określone kolumny i ograniczenia złożonego FK (klucza obcego).

Teraz piszemy zapytanie. Chcemy wierszy, w których:

FOR k.*, t.*, b.*, s.*, sb.* (
    batch = b.id AND teacher = t.name AND student = s.name
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, b.date)
AND student(s.id, s.name, s.location)
AND student-batch(sb.id, sb.student_id, sb.batch_id)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND s.id = k.student_id
AND sb.student_id = k.student_id
AND sb.batch_id = b.id
AND @date = b.date)

Wygląda to jak predykat ograniczenia z różnymi kolumnami zwrotów i dodanymi wierszami. SQL jest tak samo bezpośrednio tłumaczony. Dodajemy sprzężenie z uczniem, aby uzyskać nazwiska uczniów. Dodajemy sprzężenie z partiami uczniów, ponieważ ograniczenie nie radzi sobie z tym; konteksty korzystające z zapytania ograniczającego sprawdź, czy znajdują się w nim podwiersze student-batch (student_id, batch_id).

SELECT b.id AS batch, t.name AS teacher, s.name AS student
FROM takes k JOIN teacher t JOIN batch b JOIN student s JOIN student-batch sb
WHERE ... AND @date = date

Możesz wypróbować wersję ON:

SELECT b.id AS Batch, t.name AS Teacher, s.name AS Student
FROM takes k
JOIN teacher t ON k.subject_id = t.subject_id
JOIN batch b ON t.id = b.teacher_id
JOIN ...
WHERE @date = b.date



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nie można przekonwertować varchar na datetime w MySql

  2. Błąd krytyczny:wywołanie funkcji elementu członkowskiego query() na null

  3. Czy istnieje sposób na zwrócenie identyfikatora wiersza, który właśnie został utworzony w MySQL za pomocą PHP?

  4. Pymysql Cursor.fetchall() / Fetchone() Zwraca Brak

  5. błąd separatora mysql