{"id":101867,"date":"2024-04-11T00:20:16","date_gmt":"2024-04-11T00:20:16","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=101867"},"modified":"2026-04-15T18:19:06","modified_gmt":"2026-04-15T18:19:06","slug":"how-to-use-any-sql-database-with-rust","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/web\/how-to-use-any-sql-database-with-rust\/","title":{"rendered":"Rust SQL Databases with Diesel ORM: CRUD Operations Guide"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-executive-summary\">Executive Summary<\/h2>\n\n\n\n<p><strong>Diesel is Rust&#8217;s most widely-used ORM for SQL databases &#8211; supporting PostgreSQL, MySQL, and SQLite. It provides type-safe query building through a derive-macro system where Rust structs are mapped to database tables at compile time, catching schema mismatches before runtime. This article walks through using Diesel for SQL database access in Rust: setting up a database connection via an .env file, defining struct mappings with Diesel&#8217;s Queryable and Insertable derive macros, and performing CRUD operations &#8211; insert, query, update, delete &#8211; with Diesel&#8217;s API. PostgreSQL is used throughout, but the same patterns apply to MySQL and SQLite with driver changes.<\/strong><\/p>\n\n\n\n<p>Rust is emerging as a frontrunner for ensuring memory safety without sacrificing performance. Its growing popularity isn\u2019t solely based on the \u201cfearless concurrency\u201d mantra but also on its expanding ecosystem that fosters integration with various technologies. A domain Rust proves to be formidable is database interaction, and a pivotal player in this realm is the Diesel ORM. Diesel is an ORM and query builder designed with the philosophy of type safety and a simple API that primes application performance.<\/p>\n\n\n\n<p>In this article, I will demonstrate how to get up and running with Rust, connecting to SQL databases using the <a href=\"https:\/\/diesel.rs\/\">Diesel ORM<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-getting-started-using-sql-databases-with-rust\"><a id=\"post-101867-_eiwxci28o4fz\"><\/a>Getting Started Using SQL Databases With Rust<\/h2>\n\n\n\n<p>You\u2019ll need to<a href=\"https:\/\/www.rust-lang.org\/tools\/install\"> download and install Rust<\/a> and your preferred SQL database management system to interact with SQL databases through Rust. Diesel. In this tutorial, we will use SQLite as the DBMS, but you can use your preferred relational database<\/p>\n\n\n\n<p>After you\u2019ve installed Rust and a preferred SQL DBMS that Diesel supports, <code>you<\/code> can proceed to create a new Rust project with <a href=\"https:\/\/doc.rust-lang.org\/cargo\/commands\/cargo-init.html\">Cargo\u2019s init command<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cargo init<\/pre>\n\n\n\n<p>The <code>cargo<\/code> init command initializes the new project and adds a <code>cargo.toml<\/code> file in the root directory for dependency management.<\/p>\n\n\n\n<p>Next, you\u2019ll add Diesel as a dependency and install the <code>diesel_cli<\/code> tool to start working with databases.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># add diesel to dependencies with sqlite feature\ncargo add diesel --features \"sqlite\"\n\n# install diesel_cli \ncargo install diesel_cli\nchange to: cargo install diesel_cli --no-default-features --features sqlite\n\n#note: may get errors about \u201cnote: LINK : fatal error LNK1181: cannot open input file 'sqlite3.lib'\u201d if so, go to: https:\/\/github.com\/diesel-rs\/diesel\/issues\/487\n\n# add dotenv to dependencies\ncargo add dotenv<\/pre>\n\n\n\n<p>You need these tools to set up and use an SQL database with Diesel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-database-setup-with-diesel\"><a id=\"post-101867-_ob571juow9vv\"><\/a>Database Setup With Diesel<\/h2>\n\n\n\n<p>Setting up a database and connecting to a database with Diesel is a straightforward process.<\/p>\n\n\n\n<p>First, create an environment variables .env file in the root directory of your project and add your database connection string with the KEY DATABASE_URL.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#database connection string example\nDATABASE_URL=sqlite:\/\/\/database.sqlite<\/pre>\n\n\n\n<p>Then, run the <code>diesel setup<\/code> command to set up the database for your project.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel setup<\/pre>\n\n\n\n<p>On running the command, Diesel creates a <code>migrations<\/code> directory, validates the connection to the database, and runs existing migrations.<\/p>\n\n\n\n<p>Here\u2019s how you can setup migrations with the <code>diesel migrations generate<\/code> command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel migration generate create_human<\/pre>\n\n\n\n<p>The command will generate two SQL files in the <code>migrations<\/code> directory: <code>up.sql<\/code> and <code>down.sql<\/code>.<\/p>\n\n\n\n<p>You can write the SQL for your database table definitions in the <code>up.sql<\/code> file and the SQL query to drop the tables in the <code>down.sql<\/code> file.<\/p>\n\n\n\n<p>Here\u2019s an example of content for the <code>up.sql<\/code> file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Your SQL goes here\nCREATE TABLE \"human\"\n(\n    \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n    \"first_name\" TEXT NOT NULL,\n    \"last_name\" TEXT NOT NULL,\n    \"age\" INTEGER NOT NULL,\n    \"username\" TEXT,\n    \"email\" TEXT,\n    \"location\" TEXT\n);<\/pre>\n\n\n\n<p>Then your <code>down.sql<\/code> file should look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">DROP TABLE \"human\"<\/pre>\n\n\n\n<p>After writing the SQL files, you can run the <code>migration run<\/code> command to run migrations.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel migration run<\/pre>\n\n\n\n<p>You can use the <code>migration redo<\/code> command to revert previous migrations:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel migration redo<\/pre>\n\n\n\n<p>Diesel generates a <code>schema.rs<\/code> file in your <code>src<\/code> folder, and you can print the contents of the file with the <code>diesel print-schema<\/code> command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel print-schema<\/pre>\n\n\n\n<p>The output of the command should match the contents of your <code>src\/schema.rs<\/code> file as thus:<\/p>\n\n\n\n<p>You can connect to your SQLite database with Diesel\u2019s <code>SqliteConnection::establish<\/code> function that takes in the database URL and connects to the database:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/src\/model.rs\n\nuse std::env;\nuse diesel::prelude::*;\nuse dotenv::dotenv;\n\npub fn establish_connection() -&gt; SqliteConnection {\n    dotenv().ok();\n    let database_url = env::var(\"DATABASE_URL\").expect(\n                           \"DATABASE_URL must be set\");\n    SqliteConnection::establish(&amp;database_url)\n        .unwrap_or_else(|_| panic!(\n               \"Error connecting to the database: {}\", database_url))\n}<\/pre>\n\n\n\n<p>The <code>establish_connection()<\/code> function connects to the database and returns an SQLite connection instance that you can use for operations on the database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-basic-crud-operations\"><a id=\"post-101867-_9330g3cqg71i\"><\/a>Basic CRUD Operations<\/h2>\n\n\n\n<p>CRUD (Create, Read, Update, Delete) operations form the basis for most database operations, so you\u2019ll need to understand how to perform those operations to grasp the fundamentals of working with Diesel.<\/p>\n\n\n\n<p>Here\u2019s the list of imports and statements you\u2019ll need throughout the CRUD operations.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#![feature(proc_macro_hygiene, decl_macro)]\nextern crate diesel;\nmod schema;\nmod database;\nuse crate::database::establish_connection;\nuse diesel::prelude::*;<\/pre>\n\n\n\n<p>The <code>diesel::prelude::*<\/code> statement imports most of Diesel\u2019s functionalities.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-creating-inserting-records-into-a-database\"><a id=\"post-101867-_xita6zkh08d8\"><\/a>Creating (Inserting) Records into a Database<\/h3>\n\n\n\n<p>Diesel provides an<code>insert_into<\/code> function that you can use to insert data into your database.<\/p>\n\n\n\n<p>Here\u2019s a struct that matches the data you\u2019d want to insert. Notice the macro definitions for the operation <code>Insertable<\/code> and <code>table_name = schema::human<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Specify the fully-qualified path for the table_name attribute#[derive(Insertable)]\n#[diesel(table_name = schema::human)]\npub struct NewHuman {\n    pub first_name: String,\n    pub last_name: String,\n    pub age: i32,\n    pub username: String,\n    pub email: String,\n    pub location: String,\n}<\/pre>\n\n\n\n<p>You\u2019ll initialize the <code>NewHuman<\/code> struct and use the instance to insert data into the database as thus:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let mut connection = establish_connection();\n    let new_human = NewHuman {\n        first_name: String::from(\"John\"),\n        last_name: String::from(\"Doe\"),\n        age: 30,\n        username: String::from(\"johndoe\"),\n        email: String::from(\"john.doe@example.com\"),\n        location: String::from(\"New York\"),\n    };\n    diesel::insert_into(schema::human::table).values(&amp;new_human).execute(&amp;mut connection).expect(\"Error saving new human\");\n}<\/pre>\n\n\n\n<p>The <code>main<\/code> function establishes a connection to the database with the <code>establish_connection<\/code> function and inserts the <code>new_human<\/code> struct instance into the database with the <code>insert_into<\/code> function\u2019s <code>values<\/code> function.<\/p>\n\n\n\n<p>Here\u2019s the result of the insert operation:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1828\" height=\"642\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-1-2.png\" alt=\"\" class=\"wp-image-101880\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-querying-reading-data-from-the-database\"><a id=\"post-101867-_wmmd8d4k0tsj\"><\/a>Querying (Reading) Data From the Database<\/h3>\n\n\n\n<p>The struct for query operations will differ from the struct for insert operations, especially the Derive macro.<\/p>\n\n\n\n<p>Here\u2019s the struct for an insert operation into the Human table:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#[derive(Debug, Queryable)]\npub struct Human {\n    pub id: i32,\n    pub first_name: String,\n    pub last_name: String,\n    pub age: i32,\n    pub username: Option&lt;String&gt;, \n        \/\/ Use Option for nullable columns\n    pub email: Option&lt;String&gt;,    \n       \/\/ Use Option for nullable columns\n    pub location: Option&lt;String&gt;, \n       \/\/ Use Option for nullable columns\n}<\/pre>\n\n\n\n<p>You can use the <code>load<\/code> method on the table to load all the entries in the <code>human<\/code> table:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let mut connection = establish_connection();\n    let humans = human::table\n        .load::&lt;Human&gt;(&amp;mut connection)\n        .expect(\"Error loading humans\");\n    println!(\"{:?}\", humans);\n}<\/pre>\n\n\n\n<p>Here, the <code>main<\/code> function loads all the entries in the database with the <code>load<\/code> method after establishing a connection to the database. The <code>main<\/code> function prints the entries to the console.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"693\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-2-2.png\" alt=\"\" class=\"wp-image-101881\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-updating-database-entries\"><a id=\"post-101867-_wgws5ioh3x1c\"><\/a>Updating Database Entries<\/h3>\n\n\n\n<p>You\u2019ll need to implement the <code>AsChangeset<\/code> derive macro for your update struct to update entries in the database.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#[derive(Queryable, AsChangeset, Identifiable)]\n#[diesel(table_name = schema::human)]\nstruct UpdateHuman {\n    pub id: i32,\n    pub first_name: String,\n    pub last_name: String,\n    pub age: i32,\n    pub username: Option&lt;String&gt;,\n    pub email: Option&lt;String&gt;,\n    pub location: Option&lt;String&gt;,\n}<\/pre>\n\n\n\n<p>The <code>UpdateHuman<\/code> struct is the struct for update operations on the <code>human<\/code> table.<\/p>\n\n\n\n<p>You\u2019ll use the <code>update<\/code> function to update entries in your database tables:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    use crate::schema::human::dsl::*;\n    let mut connection = establish_connection();\n    let id_to_update = 1; \n      \/\/ Replace with the ID of the human you want to update\n    let human_update = UpdateHuman {\n        id: 2,\n        first_name: \"Janeen\".to_string(),\n        last_name: \"Elixir\".to_string(),\n        age: 30,\n        username: Some(\"elixir\".to_string()),\n        email: Some(\"jelixir@example.com\".to_string()),\n        location: Some(\"Pars\".to_string()),\n    };\n    let updated_rows = diesel::update(human.find(id_to_update))\n        .set(&amp;human_update)\n        .execute(&amp;mut connection)\n        .expect(\"Failed to update student\");\n    println!(\"{:?}\", updated_rows);\n}<\/pre>\n\n\n\n<p>The <code>main<\/code> function uses an <code>id<\/code> to search the database with the <code>find<\/code> function on the table instance before proceeding with the update operation if the entry exists. The <code>diesel::update<\/code> function updates the table with the new entry with the set function.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-deleting-entries-from-the-database\"><a id=\"post-101867-_u8pacz91ir1u\"><\/a>Deleting Entries From the Database<\/h3>\n\n\n\n<p>You can use the <code>delete<\/code> function to delete database entries based on an ID.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let id_to_delete = 1;\n    let mut connection = establish_connection();\n    let deleted_rows = diesel::delete(human.find(id_to_delete)).execute(&amp;mut connection)?;\n    println!(\"Deleted {} rows.\", deleted_rows);\n}<\/pre>\n\n\n\n<p>The <code>main<\/code> function searches for the entry with the id through the find function that the <code>delete<\/code> function takes in and executes the delete operation through the established connection.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-popular-database-operations-with-diesel\"><a id=\"post-101867-_vtch1pv76hwd\"><\/a>Popular Database Operations With Diesel<\/h2>\n\n\n\n<p>Diesel supports more operations than just CRUD operations. You can also work with multiple tables and perform more complex operations like storing a list of entries in the database:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-storing-a-list-of-entries-into-the-database\"><a id=\"post-101867-_qizhswtd7iq\"><\/a>Storing a List of Entries into the Database<\/h3>\n\n\n\n<p>One of the ways you can store a list of entries in the database is using a vector of structs that you\u2019ll iterate over and insert the values.<\/p>\n\n\n\n<p>Here\u2019s how you can insert a vector of three structs (three entries) into the database:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let mut connection = establish_connection();\n    let new_humans = vec![\n        NewHuman {\n            first_name: String::from(\"John\"),\n            last_name: String::from(\"Doe\"),\n            age: 30,\n            username: String::from(\"johndoe\"),\n            email: String::from(\"john.doe@example.com\"),\n            location: String::from(\"New York\"),\n        },\n        NewHuman {\n            first_name: String::from(\"Alice\"),\n            last_name: String::from(\"Smith\"),\n            age: 28,\n            username: String::from(\"alicesmith\"),\n            email: String::from(\"alice.smith@example.com\"),\n            location: String::from(\"Los Angeles\"),\n        },\n        NewHuman {\n            first_name: String::from(\"David\"),\n            last_name: String::from(\"Johnson\"),\n            age: 35,\n            username: String::from(\"davidjohnson\"),\n            email: String::from(\"david.johnson@example.com\"),\n            location: String::from(\"Chicago\"),\n        },\n    ];\n    \/\/ Insert the new_humans vector into the database\n    for new_human in new_humans {\n        diesel::insert_into(schema::human::table)\n            .values(&amp;new_human)\n            .execute(&amp;mut connection)\n            .expect(\"Error inserting human\");\n    }\n}<\/pre>\n\n\n\n<p>After declaring three struct instances in the <code>new_humans<\/code> vector, the <code>main<\/code> function uses a for-range loop to loop through the structs and insert the values into the database with the <code>insert_into<\/code> function.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"578\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-3-2.png\" alt=\"\" class=\"wp-image-101882\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Working with multiple tables is similar to working with single tables, except you\u2019ll have to set up migrations for the tables individually.<\/p>\n\n\n\n<p>Here\u2019s how you can generate migrations for two tables named <code>item<\/code> and <code>item_type<\/code>, respectively.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel migration generate item\n\ndiesel migration generate item_type<\/pre>\n\n\n\n<p>Now you can fill each table&#8217;s up.sql and down.sql files as usual to create and then drop the structures.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- migrations\/2023-09-23-145306_item\n-- Your SQL goes here\n-- Table definition for items\nCREATE TABLE IF NOT EXISTS items\n(\n    id            INTEGER PRIMARY KEY AUTOINCREMENT,\n    item_name     TEXT     NOT NULL,\n    item_type_id  INTEGER  NOT NULL,\n    acquired_time DATETIME NOT NULL,\n    FOREIGN KEY (item_type_id) REFERENCES item_types (id)\n);\n\n-- code to drop items\nDROP TABLE items\n\n-- migrations\/2023-09-23-145316_item_type\n-- Your SQL goes here\nCREATE TABLE IF NOT EXISTS item_types\n(\n    id   INTEGER PRIMARY KEY AUTOINCREMENT,\n    name TEXT NOT NULL\n);\n\n-- code to drop item_types\nDROP TABLE item_types<\/pre>\n\n\n\n<p>Now run the <code>diesel migration run<\/code> command to complete the setup process. Your <code>schema.rs<\/code> file should look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">diesel::table! {\n    items (id) {\n        id -&gt; Integer,\n        item_name -&gt; Text,\n        item_type_id -&gt; Integer,\n        acquired_time -&gt; Timestamp,\n    }\n}\ndiesel::table! {\n    item_types (id) {\n        id -&gt; Integer,\n        name -&gt; Text,\n    }\n}\ndiesel::joinable!(items -&gt; item_types (item_type_id));\ndiesel::allow_tables_to_appear_in_same_query!(\n    item_types,\n    items,\n);<\/pre>\n\n\n\n<p>Now that you\u2019ve set up your database migrations, you can proceed to other operations, like inserting data into the tables.<\/p>\n\n\n\n<p>Here\u2019s the list of imports you\u2019ll need for the insert operation.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">extern crate diesel;\n\nuse chrono::prelude::*;\nuse diesel::prelude::*;\nuse diesel::dsl::now;\nuse diesel::sql_types::Timestamp;\nuse crate::database::establish_connection;\n\n\/\/ Import the table and schema macros.\nuse crate::schema::{item_types, items};\n\n<\/pre>\n\n\n\n<p>Additionally, here are the structs you need for the insert operation:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#[derive(Insertable)]\n#[table_name = \"item_types\"]\nstruct NewItemType&lt;'a&gt; {\n    name: &amp;'a str,\n}\n#[derive(Insertable)]\n#[table_name = \"items\"]\nstruct NewItem&lt;'a&gt; {\n    item_name: &amp;'a str,\n    item_type_id: i32,\n    acquired_time: NaiveDateTime,\n}<\/pre>\n\n\n\n<p>Notice that the structs implement<code>Insertable<\/code> for Diesel to be able to insert their instances into the database.<\/p>\n\n\n\n<p>You can use Diesel\u2019s <code>insert_into<\/code> function to insert entries in the tables on instantiation as usual:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let mut connection = establish_connection();\n    let new_item = NewItem {\n        item_name: \"Book\",\n        item_type_id: 1,\n        acquired_time: Utc::now().naive_utc(),\n    };\n    diesel::insert_into(items::table)\n        .values(&amp;new_item)\n        .execute(&amp;mut connection)\n        .expect(\"Error saving new item\");\n    let new_item_type = NewItemType { name: \"Education\" };\n    diesel::insert_into(item_types::table)\n        .values(&amp;new_item_type)\n        .execute(&amp;mut connection)\n        .expect(\"Error saving new item type\");\n}<\/pre>\n\n\n\n<p>The <code>main<\/code> function inserts data into the <code>item<\/code> and <code>item_type<\/code> tables with the <code>insert_into<\/code> function that takes in the table declarations from the <code>schema.rs<\/code> file.<\/p>\n\n\n\n<p>Here\u2019s the result of the insert operation on the <code>item<\/code> table:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1318\" height=\"626\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-4-2.png\" alt=\"\" class=\"wp-image-101883\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Also, here\u2019s the result of the insert operation on the <code>item_type<\/code> table:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1440\" height=\"662\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-5-2.png\" alt=\"\" class=\"wp-image-101884\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>You can query the database for the data from the <code>item<\/code> and <code>item_type<\/code> tables.<\/p>\n\n\n\n<p>Diesel provides robust support for writing raw SQL in its <code>sql_query<\/code> function that you can use for functionalities Diesel doesn&#8217;t support.<\/p>\n\n\n\n<p>Here are the imports you need for the query operation, including Diesel\u2019s <code>sql_query<\/code> function import:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">extern crate diesel;\nmod schema;\nmod database;\nuse crate::database::establish_connection;\nuse diesel::prelude::*;\nuse diesel::sql_query;<\/pre>\n\n\n\n<p>You can declare a struct that matches your schema to query the database with a struct as thus:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#[derive(Debug, QueryableByName)]\n#[diesel(table_name = schema::item_types)]\nstruct ItemType {\n    id: i32,\n    name: String,\n}\n#[derive(Debug, QueryableByName)]\n#[diesel(table_name = schema::items)]\nstruct Item {\n    id: i32,\n    item_name: String,\n    acquired_time: chrono::NaiveDateTime,\n    \/\/ Assuming you use chrono for datetime fields\n    item_type_id: i32,\n}<\/pre>\n\n\n\n<p>The structs implement <code>Debug<\/code> and <code>QueryableByName<\/code> for the query operation using raw SQL.<\/p>\n\n\n\n<p>Here\u2019s how you can query the tables with the item <code>ID<\/code> using raw SQL:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fn main() {\n    let mut connection = establish_connection();\n    let item_type_id_to_retrieve = 1;\n    \/\/ Using raw SQL to retrieve the ItemType\n    let item_type: ItemType = \n                sql_query(\"SELECT * FROM item_types WHERE id = $1\")\n        .bind::&lt;diesel::sql_types::Integer, _&gt;(item_type_id_to_retrieve)\n        .get_result(&amp;mut connection)\n        .expect(\"Failed to find item type by ID\");\n    \/\/ Using raw SQL to retrieve items of \n    \/\/the specified item type\n    let items_of_type: Vec&lt;Item&gt; \n      = sql_query(\n            \"SELECT * FROM items WHERE item_type_id = $1\")\n        .bind::&lt;diesel::sql_types::Integer, _&gt;(item_type.id)\n        .load(&amp;mut connection)\n        .expect(\"Failed to load items of item type\");\n    println!(\"Items of type '{}':\", item_type.name);\n    for item in items_of_type {\n        println!(\n            \"Item ID: {}, Name: {}, Acquired Time: {:?}\",\n            item.id, item.item_name, item.acquired_time\n        );\n    }\n}<\/pre>\n\n\n\n<p>The <code>main<\/code> function connects to the database with the <code>establish_connection<\/code> function before the <code>item_type_id_to_retrieve<\/code> declaration. The string in the <code>sql_query<\/code> function is the SQL statement for the operation, and you can bind the result to structs with the <code>bind<\/code> function.<\/p>\n\n\n\n<p>The <code>main<\/code> function uses a for-range loop to print the fields of the struct instance.<\/p>\n\n\n\n<p>Here\u2019s the result of the operation:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1708\" height=\"830\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/03\/word-image-101867-6-2.png\" alt=\"\" class=\"wp-image-101885\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Diesel also provides functionality for code-first relationships on the Relations page that you can check out.<\/p>\n\n\n\n<p>Note: building SQL to execute can lead to errors. Another name for this is dynamic SQL, which can sometimes allow someone to form a string that can cause harm to your database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\"><a id=\"post-101867-_qer9mi4m5u4e\"><\/a>Conclusion<\/h2>\n\n\n\n<p>You\u2019ve deeply explored how to use Diesel to interact with SQL databases in your Rust apps. You learned how to set up your database, connect to databases, perform CRUD operations, and work with multiple tables, amongst other operations.<\/p>\n\n\n\n<p>You can do so much with Diesel, including building REST APIs. You can use tools like <a href=\"https:\/\/actix.rs\/\">Actix<\/a> and <a href=\"https:\/\/rocket.rs\/\">Rocket<\/a> to build APIs with Diesel. Since Diesel provides an interface for writing RAW SQL and has excellent community support,<\/p>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs: How to Use Any SQL Database With Rust<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What is Diesel and how does it compare to other Rust database libraries?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Diesel is a compile-time safe ORM for Rust supporting PostgreSQL, MySQL, and SQLite. It generates type-safe SQL queries using Rust&#8217;s type system &#8211; column type mismatches or missing tables produce compile errors rather than runtime panics. Main alternatives: sqlx (async-first, raw SQL queries with compile-time checking, broader database support), Rusqlite (SQLite-specific, lower-level), and sea-orm (async ORM inspired by ActiveRecord). Diesel is a good choice when you prefer a traditional ORM model with struct-based mapping; sqlx is better when you want to write raw SQL and still catch errors at compile time.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. How do I connect Rust to a PostgreSQL database with Diesel?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Add diesel = { version = &#8220;2.0&#8221;, features = [&#8220;postgres&#8221;] } and dotenvy to your Cargo.toml. Create a .env file with DATABASE_URL=postgres:\/\/user:password@localhost\/dbname. In code: use diesel::prelude::*; use dotenvy::dotenv; let database_url = std::env::var(&#8220;DATABASE_URL&#8221;).expect(&#8220;DATABASE_URL must be set&#8221;); let connection = PgConnection::establish(&amp;database_url)?; Run diesel setup and diesel migration run to create and apply migrations. Define your table schema in schema.rs using Diesel&#8217;s table! macro.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. How do I perform a SELECT query with Diesel in Rust?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Define a struct with the Queryable derive macro, matching the column types in your table. Use Diesel&#8217;s query DSL: let results = users.filter(age.gt(18)).limit(10).load::&lt;User&gt;(&amp;mut conn)?; The filter, order, limit, and select methods build a type-safe query &#8211; Diesel validates column names and types at compile time against the schema.rs definitions. For raw SQL when you need query features Diesel&#8217;s DSL doesn&#8217;t support, use diesel::sql_query(&#8220;SELECT * FROM users WHERE &#8230;&#8221;).load::&lt;User&gt;(&amp;mut conn)?<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. Does Diesel support async Rust database access?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Diesel&#8217;s core API is synchronous. For async Rust applications (Tokio, async-std), use diesel-async, a separate crate that provides async versions of Diesel&#8217;s connection and query methods. Alternatively, sqlx is built async-first and may be a better fit for async-heavy applications. If using Diesel in an async context without diesel-async, run blocking Diesel calls in a Tokio spawn_blocking task to avoid blocking the async runtime thread.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Connect Rust applications to SQL databases using the Diesel ORM. Covers database setup with .env configuration, basic CRUD operations (insert, query, update, delete), batch inserts, and Diesel&#8217;s derive macros for struct-to-table mapping.&hellip;<\/p>\n","protected":false},"author":340771,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[53,147005],"tags":[159071],"coauthors":[147592],"class_list":["post-101867","post","type-post","status-publish","format-standard","hentry","category-featured","category-web","tag-rust"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/101867","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/340771"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=101867"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/101867\/revisions"}],"predecessor-version":[{"id":109776,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/101867\/revisions\/109776"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=101867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=101867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=101867"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=101867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}