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

Связывание через таблицу связи в Rust

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

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

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

use rusqlite::{Connection, params}; fn link_demo() -> Result<(), rusqlite::Error> { let _ = std::fs::remove_file("app.db"); let conn = Connection::open("app.db")?; conn.execute("PRAGMA foreign_keys = ON", [])?; conn.execute( "CREATE TABLE post ( id INTEGER PRIMARY KEY, title TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE tag ( id INTEGER PRIMARY KEY, name TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE post_tag ( post_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, FOREIGN KEY (post_id) REFERENCES post(id), FOREIGN KEY (tag_id) REFERENCES tag(id) )", [], )?; conn.execute( "INSERT INTO post (title) VALUES (?1)", params!["hello"], )?; conn.execute("INSERT INTO tag (name) VALUES (?1)", params!["news"])?; conn.execute("INSERT INTO tag (name) VALUES (?1)", params!["draft"])?; conn.execute( "INSERT INTO post_tag (post_id, tag_id) VALUES (?1, ?2)", params![1, 1], )?; conn.execute( "INSERT INTO post_tag (post_id, tag_id) VALUES (?1, ?2)", params![1, 2], )?; Ok(()) } fn main() { match link_demo() { Ok(()) => println!("links ready"), Err(e) => println!("{}", e), } }

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

use rusqlite::{Connection, params}; fn read_pairs() -> Result<(), rusqlite::Error> { let _ = std::fs::remove_file("app.db"); let conn = Connection::open("app.db")?; conn.execute("PRAGMA foreign_keys = ON", [])?; conn.execute( "CREATE TABLE post ( id INTEGER PRIMARY KEY, title TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE tag ( id INTEGER PRIMARY KEY, name TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE post_tag ( post_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, FOREIGN KEY (post_id) REFERENCES post(id), FOREIGN KEY (tag_id) REFERENCES tag(id) )", [], )?; conn.execute( "INSERT INTO post (title) VALUES (?1)", params!["hello"], )?; conn.execute("INSERT INTO tag (name) VALUES (?1)", params!["news"])?; conn.execute( "INSERT INTO post_tag (post_id, tag_id) VALUES (?1, ?2)", params![1, 1], )?; let mut stmt = conn.prepare( "SELECT p.title, t.name FROM post p INNER JOIN post_tag pt ON pt.post_id = p.id INNER JOIN tag t ON pt.tag_id = t.id", )?; let rows = stmt.query_map([], |row| { let title: String = row.get(0)?; let tag_name: String = row.get(1)?; Ok((title, tag_name)) })?; for item in rows { let (title, tag_name) = item?; println!("{} {}", title, tag_name); } Ok(()) } fn main() { match read_pairs() { Ok(()) => {} Err(e) => println!("{}", e), } }

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

CREATE TABLE post ( id INTEGER PRIMARY KEY, title TEXT NOT NULL ); CREATE TABLE tag ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE post_tag ( post_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, FOREIGN KEY (post_id) REFERENCES post(id), FOREIGN KEY (tag_id) REFERENCES tag(id) );

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

Даны заполненные post, tag и post_tag из первого примера урока. Напишите запрос, который выведет имена всех меток поста с заголовком "hello".

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

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