Rustで直接SQLを書いてMySQLからデータを抽出する方法
はじめに
RustでMySQLを使う場合、事前に構造体を定義する方法が主流ですが、
直接SQLを書きたいケースも多いのではないでしょうか。
今回はDieselを使って直SQLでデータを抽出する方法を紹介します。
用意したデータ
ソースはこちらから
テーブル
monster
monster_id
name
type1_id
type2_id
1
フシギダネ
5
8
2
フシギソウ
5
8
3
フシギバナ
5
8
4
ヒトカゲ
2
NULL
5
リザード
2
NULL
6
リザードン
2
10
7
ゼニガメ
3
NULL
8
カメール
3
NULL
9
カメックス
3
NULL
type
type_id
type_name
1
ノーマル
2
ほのお
3
みず
4
でんき
5
くさ
6
こおり
7
かくとう
8
どく
9
じめん
10
ひこう
11
エスパー
12
むし
13
いわ
14
ゴースト
15
ドラゴン
16
あく
17
はがね
18
フェアリー
MySQLに接続
Dieselというライブラリを使用します。
https://github.com/diesel-rs/diesel
[dependencies]
diesel = { version = "*", features = ["mysql"] }
DBに接続するための関数を作ります。
use diesel::mysql::MysqlConnection;
use diesel::prelude::*;
use dotenv::dotenv;
pub fn establish_connection() -> MysqlConnection {
let database_url = "mysql://[user]:[password]@host[:port][/database]";
MysqlConnection::establish(&database_url)
.expect(&format!("Error connecting to {}", database_url))
}
※mysql://[user]:[password]@host[:port][/database]には実際の接続情報を入力してください。
シンプルなSQLを書いてみる
use crate::utils::establish_connection;
use diesel::deserialize::QueryableByName;
use diesel::mysql::MysqlConnection;
use diesel::prelude::*;
use diesel::sql_query;
mod utils;
type DB = diesel::mysql::Mysql;
#[derive(Debug)]
pub struct Monster {
monster_id: i32,
name: String,
type1_id: i32,
type2_id: Option<i32>,
}
impl QueryableByName<DB> for Monster {
fn build<R: diesel::row::NamedRow<diesel::mysql::Mysql>>(
row: &R,
) -> diesel::deserialize::Result<Self> {
Ok(Monster {
monster_id: row.get("monster_id")?,
name: row.get("name")?,
type1_id: row.get("type1_id")?,
type2_id: row.get("type2_id")?,
})
}
}
fn simple_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<Monster> = sql_query(
"
SELECT
monster_id,
name,
type1_id,
type2_id
FROM
monster
",
)
.load(&connection)
.unwrap();
println!("{:?}", monsters)
}
use crate::utils::establish_connection;
use diesel::deserialize::QueryableByName;
use diesel::mysql::MysqlConnection;
use diesel::prelude::*;
use diesel::sql_query;
mod utils;
type DB = diesel::mysql::Mysql;
#[derive(Debug)]
pub struct Monster {
monster_id: i32,
name: String,
type1_id: i32,
type2_id: Option<i32>,
}
impl QueryableByName<DB> for Monster {
fn build<R: diesel::row::NamedRow<diesel::mysql::Mysql>>(
row: &R,
) -> diesel::deserialize::Result<Self> {
Ok(Monster {
monster_id: row.get("monster_id")?,
name: row.get("name")?,
type1_id: row.get("type1_id")?,
type2_id: row.get("type2_id")?,
})
}
}
fn simple_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<Monster> = sql_query(
"
SELECT
monster_id,
name,
type1_id,
type2_id
FROM
monster
",
)
.load(&connection)
.unwrap();
println!("{:?}", monsters)
}
直接SQLを使うには、diesel::sql_query
を使います。
diesel::deserialize::QueryableByName
を使ってデータを受け取るための型を定義します。
PreparedStatementっぽいこと
use diesel::sql_types::Text;
use diesel::sql_types::Integer;
fn prepared_statement_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<Monster> = sql_query(
"
SELECT
monster_id,
name,
type1_id,
type2_id
FROM
monster
WHERE
monster_id = ?
OR name = ?
",
)
.bind::<Integer, _>(4)
.bind::<Text, _>("ヒトカゲ")
.load(&connection)
.unwrap();
println!("{:?}", monsters[0])
}
use diesel::sql_types::Text;
use diesel::sql_types::Integer;
fn prepared_statement_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<Monster> = sql_query(
"
SELECT
monster_id,
name,
type1_id,
type2_id
FROM
monster
WHERE
monster_id = ?
OR name = ?
",
)
.bind::<Integer, _>(4)
.bind::<Text, _>("ヒトカゲ")
.load(&connection)
.unwrap();
println!("{:?}", monsters[0])
}
SQLの中に?
を書いて、
.bind::<Integer, _>(4)
や.bind::<Text, _>("ヒトカゲ")
と書くことで安全にSQLの中に数値や文字列を挿入することができます。
JOIN
#[derive(Debug)]
pub struct MonsterFull {
monster_id: i32,
name: String,
type1_id: i32,
type2_id: Option<i32>,
type1_name: String,
type2_name: Option<String>,
}
impl QueryableByName<DB> for MonsterFull {
fn build<R: diesel::row::NamedRow<diesel::mysql::Mysql>>(
row: &R,
) -> diesel::deserialize::Result<Self> {
Ok(MonsterFull {
monster_id: row.get("monster_id")?,
name: row.get("name")?,
type1_id: row.get("type1_id")?,
type2_id: row.get("type2_id")?,
type1_name: row.get("type1_name")?,
type2_name: row.get("type2_name")?,
})
}
}
fn complex_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<MonsterFull> = sql_query(
"
SELECT
m.monster_id,
m.name,
m.type1_id,
m.type2_id,
t1.type_name AS type1_name,
t2.type_name AS type2_name
FROM
monster m
LEFT JOIN
type t1
ON
m.type1_id = t1.type_id
LEFT JOIN
type t2
ON
m.type2_id = t2.type_id
",
)
.load(&connection)
.unwrap();
println!("{:?}", monsters);
}
#[derive(Debug)]
pub struct MonsterFull {
monster_id: i32,
name: String,
type1_id: i32,
type2_id: Option<i32>,
type1_name: String,
type2_name: Option<String>,
}
impl QueryableByName<DB> for MonsterFull {
fn build<R: diesel::row::NamedRow<diesel::mysql::Mysql>>(
row: &R,
) -> diesel::deserialize::Result<Self> {
Ok(MonsterFull {
monster_id: row.get("monster_id")?,
name: row.get("name")?,
type1_id: row.get("type1_id")?,
type2_id: row.get("type2_id")?,
type1_name: row.get("type1_name")?,
type2_name: row.get("type2_name")?,
})
}
}
fn complex_sql() {
let connection: MysqlConnection = establish_connection();
let monsters: Vec<MonsterFull> = sql_query(
"
SELECT
m.monster_id,
m.name,
m.type1_id,
m.type2_id,
t1.type_name AS type1_name,
t2.type_name AS type2_name
FROM
monster m
LEFT JOIN
type t1
ON
m.type1_id = t1.type_id
LEFT JOIN
type t2
ON
m.type2_id = t2.type_id
",
)
.load(&connection)
.unwrap();
println!("{:?}", monsters);
}
JOINなどの複雑な操作も受け取るための型さえ用意すれば簡単にできます。
おわりに
この方法を使えば、Rustから直SQLを書いてデータを抽出することができました。
直接SQLを書きたい方は是非参考にしてもらえればと思います。
Author And Source
この問題について(Rustで直接SQLを書いてMySQLからデータを抽出する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/tonio0720/items/d6d81ecebb4559a83dd7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .