Как вернуть данные одной строки в русклите? - PullRequest
0 голосов
/ 18 октября 2019

Я пишу программу, гдеМне нужно получить обратно id из последней вставки, только что созданной sqlite.

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);

Мне нужно получить возвращаемое значение sqlite id, автоматически назначаемое с помощью AUTOINCREMENT.

Iполучаю этот компилятор Ошибка:

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: Я понимаю, что строка String не подходит для вызова execute, но я не уверен, что делатьделай вместо

Я подозреваю, что должно произойти, если таблицу short_names нужно извлечь из базы данных, а затем из представления ржавчины таблицы, чтобы получить id, который соответствует short, который я пытаюсьработать с. Я использовал этот пример как отправную точку, но он разыменовал его полезность. Программа, которую я пишу, вызывает другую программу, а затем присматривает за ней во время работы этой другой программы. Чтобы сократить накладные расходы, я пытаюсь не использовать ООП для этой текущей программы.

Как мне структурировать мой запрос к базе данных, чтобы получить id, который мне нужен?

Ответы [ 2 ]

2 голосов
/ 18 октября 2019

Хорошо. Во-первых, мы будем использовать struct, потому что, в отличие от Java, это буквально эквивалентно тому, что мы не используем его в этом случае, за исключением того, что вы получаете возможность сохранять вещи tidy .

Вы пытаетесь подражать 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);
}
0 голосов
/ 23 октября 2019

In rusqlite execute не возвращает значение. Чтобы вернуть значение из sqlite-операции, вам нужно использовать prepare и вариант query. В то время как большая часть Rust позволяет вам оставлять тип вплоть до компилятора, для rusqite вам нужно присвоить принимающей переменной тип.

В настоящее время в rusqlite нет способа извлечь одну строку из запроса. Тип rows не является итератором типа, поэтому вам нужно пройти по нему с помощью цикла while, который будет выполняться на основе типа ошибки rows. После запуска цикла он вернется, что в rows нет других row, и завершится;если в запросе есть только одна строка.

Вы можете использовать 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 и id, созданные в области действия main(), все еще доступны для области действия базы данных и остальной части области действия main(). Хотя id не назначен до области действия db, но он определен вне области действия, область действия main, так что отсюда начинается время жизни id. id не должен быть изменяемым, потому что он назначается только один раз, если на самом деле есть только одна строка для извлечения, цикл while назначит ее только один раз. В противном случае, если база данных не будет работать должным образом, это приведет к ошибке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...