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

Цепочка связанных таблиц в Rust

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

Цепочка соединяет таблицы по очереди: сначала пост к пользователю, затем post_tag к посту, затем метку к post_tag. Каждый шаг сравнивает номера в условии ON.

Подготовим данные и выведем имя пользователя и имя метки:

use rusqlite::{Connection, params}; fn chain_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 user ( id INTEGER PRIMARY KEY, name TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE post ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, title TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES user(id) )", [], )?; 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 user (name) VALUES (?1)", params!["ann"])?; conn.execute( "INSERT INTO post (user_id, title) VALUES (?1, ?2)", params![1, "note"], )?; 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 u.name, t.name FROM user u INNER JOIN post p ON p.user_id = u.id INNER JOIN post_tag pt ON pt.post_id = p.id INNER JOIN tag t ON pt.tag_id = t.id ORDER BY p.id", )?; let rows = stmt.query_map([], |row| { let user_name: String = row.get(0)?; let tag_name: String = row.get(1)?; Ok((user_name, tag_name)) })?; for item in rows { let (user_name, tag_name) = item?; println!("{} {}", user_name, tag_name); } Ok(()) } fn main() { match chain_demo() { Ok(()) => {} Err(e) => println!("{}", e), } }

Фильтр по имени пользователя ставят после всех шагов цепочки:

use rusqlite::{Connection, params}; fn tags_for_ann() -> 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 user ( id INTEGER PRIMARY KEY, name TEXT NOT NULL )", [], )?; conn.execute( "CREATE TABLE post ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, title TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES user(id) )", [], )?; 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 user (name) VALUES (?1)", params!["ann"])?; conn.execute("INSERT INTO user (name) VALUES (?1)", params!["bob"])?; conn.execute( "INSERT INTO post (user_id, title) VALUES (?1, ?2)", params![1, "a"], )?; conn.execute( "INSERT INTO post (user_id, title) VALUES (?1, ?2)", params![2, "b"], )?; 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![2, 2], )?; let mut stmt = conn.prepare( "SELECT t.name FROM user u INNER JOIN post p ON p.user_id = u.id INNER JOIN post_tag pt ON pt.post_id = p.id INNER JOIN tag t ON pt.tag_id = t.id WHERE u.name = ?1", )?; let rows = stmt.query_map(params!["ann"], |row| { let tag_name: String = row.get(0)?; Ok(tag_name) })?; for item in rows { let tag_name = item?; println!("{}", tag_name); } Ok(()) } fn main() { match tags_for_ann() { Ok(()) => {} Err(e) => println!("{}", e), } }

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

CREATE TABLE user ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE post ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, title TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES user(id) ); 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) );

Товар лежит в подкатегории, подкатегория в категории. Опишите три таблицы и столбцы ссылок без текста запроса выборки.

Даны user, post, tag и post_tag как в примере урока. Напишите запрос, который выведет имя пользователя, заголовок поста и имя метки для каждой связанной тройки.

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

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