如何在rusqlite中取回一行的数据?

时间:2019-10-18 11:21:44

标签: sqlite rust

我正在编写一个程序,需要从sqlite刚刚创建的最后一次插入中恢复id

db.execute("insert into short_names (short_name) values (?1)",params![short]).expect("db insert fail");

let id = db.execute("SELECT id FROM short_names WHERE short_name = '?1';",params![&short]).query(NO_PARAMS).expect("get record id fail");

let receiver = db.prepare("SELECT id FROM short_names WHERE short_name = "+short+";").expect("");
let id = receiver.query(NO_PARAMS).expect("");
println!("{:?}",id);

我应该找回的是用AUTOINCREMENT自动分配的id值sqlite。

我遇到此编译器错误:

error[E0599]: no method named `query` found for type `std::result::Result<usize, rusqlite::Error>` in the current scope
  --> src/main.rs:91:100
   |
91 |         let id = db.execute("SELECT id FROM short_names WHERE short_name = '?1';",params![&short]).query(NO_PARAMS).expect("get record id fail");
   |                                                                                                    ^^^^^

error[E0369]: binary operation `+` cannot be applied to type `&str`
  --> src/main.rs:94:83
   |
94 |         let receiver = db.prepare("SELECT id FROM short_names WHERE short_name = "+short+";").expect("");
   |                                   ------------------------------------------------^----- std::string::String
   |                                   |                                               |
   |                                   |                                               `+` cannot be used to concatenate a `&str` with a `String`
   |                                   &str
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
   |
94 |         let receiver = db.prepare("SELECT id FROM short_names WHERE short_name = ".to_owned()+&short+";").expect("");
   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^

error[E0277]: `rusqlite::Rows<'_>` doesn't implement `std::fmt::Debug`
  --> src/main.rs:96:25
   |
96 |         println!("{:?}",id);
   |                         ^^ `rusqlite::Rows<'_>` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
   |
   = help: the trait `std::fmt::Debug` is not implemented for `rusqlite::Rows<'_>`
   = note: required by `std::fmt::Debug::fmt`

第94行:我知道rust的String不是用于execute调用的正确类型,但是我不确定该怎么做。

我怀疑需要发生的是需要将short_names表从数据库中拉出,然后从该表的rust表示形式中获取与id相匹配的short正在尝试合作。 I've been going off this example as a jumping off point, but It's dereferenced it's usefulness.我正在编写的程序会调用另一个程序,然后在另一个程序运行时对其进行照顾。为了减少开销,我正在尝试对当前程序不使用OOP。

我应该如何构造对数据库的请求以得到所需的id

2 个答案:

答案 0 :(得分:2)

好的。首先,我们使用struct,因为与Java不同,它实际上等于在这种情况下不使用一个,除非您能够保留某些东西整洁

您正在尝试模仿Connection::last_insert_rowid(),这并不是一件非常明智的事情,特别是如果您不在交易中。我们还将以一种简洁的方式为您清除此问题:

use rusqlite::{Connection};

pub struct ShortName {
    pub id: i64,
    pub name: String
}

pub fn insert_shortname(db: &Connection, name: &str) -> Result<ShortName, rusqlite::Error> {
    let mut rtn = ShortName {
        id: 0,
        name: name.to_string()
    };
    db.execute("insert into short_names (short_name) values (?)",&[name])?;
    rtn.id = db.last_insert_rowid();
    Ok(rtn)
}

您可以说服自己该测试可以使用:

#[test]
fn it_works() {
    let conn = Connection::open_in_memory().expect("Could not test: DB not created");
    let input:Vec<bool> = vec![];
    conn.execute("CREATE TABLE short_names (id INTEGER PRIMARY KEY AUTOINCREMENT, short_name TEXT NOT NULL)", input).expect("Creation failure");
    let output = insert_shortname(&conn, "Fred").expect("Insert failure");
    assert_eq!(output.id, 1);
}

答案 1 :(得分:0)

rusqliteexecute不返回值。要从sqlite操作返回值,您需要使用preparequery的变体。尽管大部分Rust都允许您将类型留给编译器,但对于rusqite,您需要给接收变量指定类型。

rusqlite当前没有办法从查询中取出一行。 rows的类型不是类型迭代器,因此您需要使用while循环对其进行处理,该循环将根据rows的错误类型进行处理。循环运行一次后,它将返回row中没有其他rows并退出;如果查询中只有一行。

您可以使用query_named修改您的打磨的sql查询。使用named_params!{}宏将使您可以使用字符串将信息发送到命令。

use rusqlite::*;

fn main() {
    let short = "lookup".to_string(); // example of a string you might use
    let id:i64;
    { // open for db work
        let db = Connection::open("YourDB.db").expect("db conn fail");
        let mut receiver = db.prepare("SELECT * FROM short_names WHERE short_name = :short;").expect("");
        let mut rows = receiver.query_named(named_params!{ ":short": short }).expect("");
        while let Some(row) = rows.next().expect("") {
            id=row.get(0).expect("");
        }
    } // close db work
    println!("{}",id);
}

在上面的示例中,我们在数据库事务周围使用{}打开了一个作用域,当数据库超出作用域时,它将自动关闭该数据库。请注意,我们创建了数据库连接,仅在{}内对数据库进行了所有工作。这允许我们跳过使用explicate命令关闭数据库的操作,这是由编译器从{}范围进行的推断得出的。在short范围内创建的变量idmain()仍可用于db范围和main()范围的其余部分。虽然id直到db作用域才分配,但是它是在作用域(即main的作用域)之外定义的,因此id的生命周期开始于此。 id不需要是可变的,因为它只分配了一次,如果实际上只有一行要检索,则while循环将只分配一次。否则,如果数据库无法正常运行,将导致错误。