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

Левое соединение в Rust

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

В Rust такой столбец читают в Option<String> или Option<i64> и разбирают через match или if let перед использованием значения.

Выведем всех пользователей и их посты, если они есть:

use rusqlite::{Connection, params}; fn all_users() -> 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("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, "pen"], )?; let mut stmt = conn.prepare( "SELECT u.name, p.title FROM user u LEFT JOIN post p ON p.user_id = u.id ORDER BY u.id, p.id", )?; let rows = stmt.query_map([], |row| { let name: String = row.get(0)?; let title: Option<String> = row.get(1)?; Ok((name, title)) })?; for item in rows { let (name, title) = item?; println!("{}", name); match title { Some(text) => println!("{}", text), None => println!("no post"), } } Ok(()) } fn main() { match all_users() { Ok(()) => {} Err(e) => println!("{}", e), } }

Для числового столбца справа подойдет Option<i64>:

use rusqlite::{Connection, params}; fn qty_for_bob() -> 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, qty INTEGER NOT NULL, FOREIGN KEY (user_id) REFERENCES user(id) )", [], )?; conn.execute("INSERT INTO user (name) VALUES (?1)", params!["bob"])?; let mut stmt = conn.prepare( "SELECT u.name, p.qty FROM user u LEFT JOIN post p ON p.user_id = u.id WHERE u.name = ?1", )?; let mut rows = stmt.query(params!["bob"])?; if let Some(row) = rows.next()? { let name: String = row.get(0)?; let qty: Option<i64> = row.get(1)?; println!("{}", name); match qty { Some(n) => println!("{}", n), None => println!("empty qty"), } } Ok(()) } fn main() { match qty_for_bob() { 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) ); INSERT INTO user (name) VALUES ('ann'); INSERT INTO user (name) VALUES ('bob'); INSERT INTO post (user_id, title) VALUES (1, 'pen');

Составьте запрос от таблицы пользователей, чтобы в результате был "bob" с подписью "no post" вместо заголовка. Прочитайте заголовок в Option<String>.

Даны таблицы team и member с полем team_id. Одна команда без участников должна попасть в вывод с пустым именем участника. Опишите, какой тип взять для имени справа при чтении строки.

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

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