Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗goSpRlMM 224 of 280 menu
◀ ▶

Связь многие ко многим в Go

Один студент может слушать несколько курсов, и один курс могут слушать многие студенты. Двух таблиц с одним полем ссылки для этого мало: ни одна сторона не может хранить список номеров в одной строке без дублирования.

Связь многие ко многим держат третьей таблицей с двумя номерами. Каждая ее строка фиксирует одну пару студент-курс, а полный набор пар собирают из нескольких строк.

Создадим справочники и таблицу student_course:

package main import ( "database/sql" "fmt" "log" "os" _ "modernc.org/sqlite" ) func main() { os.Remove("shop.db") db, err := sql.Open("sqlite", "shop.db") if err != nil { log.Fatal(err) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys = ON") if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE students ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE courses ( id INTEGER PRIMARY KEY, title TEXT NOT NULL ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE student_course ( student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, FOREIGN KEY (student_id) REFERENCES students (id), FOREIGN KEY (course_id) REFERENCES courses (id) ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(`INSERT INTO students (name) VALUES (?)`, "ann") if err != nil { log.Fatal(err) } _, err = db.Exec(`INSERT INTO courses (title) VALUES (?)`, "go") if err != nil { log.Fatal(err) } _, err = db.Exec(`INSERT INTO courses (title) VALUES (?)`, "sql") if err != nil { log.Fatal(err) } _, err = db.Exec( `INSERT INTO student_course (student_id, course_id) VALUES (?, ?)`, 1, 1, ) if err != nil { log.Fatal(err) } _, err = db.Exec( `INSERT INTO student_course (student_id, course_id) VALUES (?, ?)`, 1, 2, ) if err != nil { log.Fatal(err) } fmt.Println("links ready") }

Имена и названия курсов достают двумя шагами соединения через таблицу связи:

package main import ( "database/sql" "fmt" "log" "os" _ "modernc.org/sqlite" ) func main() { os.Remove("shop.db") db, err := sql.Open("sqlite", "shop.db") if err != nil { log.Fatal(err) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys = ON") if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE students ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE courses ( id INTEGER PRIMARY KEY, title TEXT NOT NULL ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE student_course ( student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, FOREIGN KEY (student_id) REFERENCES students (id), FOREIGN KEY (course_id) REFERENCES courses (id) ) `) if err != nil { log.Fatal(err) } _, err = db.Exec(`INSERT INTO students (name) VALUES (?)`, "ann") if err != nil { log.Fatal(err) } _, err = db.Exec(`INSERT INTO courses (title) VALUES (?)`, "go") if err != nil { log.Fatal(err) } _, err = db.Exec( `INSERT INTO student_course (student_id, course_id) VALUES (?, ?)`, 1, 1, ) if err != nil { log.Fatal(err) } rows, err := db.Query(` SELECT s.name, c.title FROM students s INNER JOIN student_course sc ON sc.student_id = s.id INNER JOIN courses c ON sc.course_id = c.id `) if err != nil { log.Fatal(err) } defer rows.Close() for rows.Next() { var studentName string var courseTitle string err = rows.Scan(&studentName, &courseTitle) if err != nil { log.Fatal(err) } fmt.Println(studentName, courseTitle) } err = rows.Err() if err != nil { log.Fatal(err) } }

Даны таблицы:

CREATE TABLE students ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE courses ( id INTEGER PRIMARY KEY, title TEXT NOT NULL ); CREATE TABLE student_course ( student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, FOREIGN KEY (student_id) REFERENCES students (id), FOREIGN KEY (course_id) REFERENCES courses (id) );

Товар может относиться к нескольким категориям, и категория может включать много товаров. Опишите имена таблиц и столбцы связи без готового текста запроса выборки.

Даны заполненные students, courses и student_course из первого примера урока. Напишите запрос, который выведет названия всех курсов студента "ann".

Скажите, почему в student_course обычно не хранят имя студента текстом, а только его номер.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить