2015-05-10 10 views
5

Mój projekt polega na zaprogramowaniu prostego ShopApp. Jedna funkcja polega na sprawdzeniu, czy jest wystarczająco dużo zapasów, aby klient mógł kupić żądaną ilość tego, co chce kupić. Funkcje wygląda (gdzie cart jest std::vector<product> i Pid oznacza identyfikator produktu):Qt: Zapisz wynik zapytania SQL w zmiennej, użyj zmiennej C++ w zapytaniu SQL

bool sqlfunctions::checkStock(){ 
    QSqlQuery query; 
    int diff, stock; 
    for(iter cursor = cart.begin();cursor!=cart.end();cursor++){ 
     query.prepare("SELECT stock FROM products WHERE id = cursor->getPid()"); 
     query.exec(); 
     // Need to save result of query into variable stock 
     stock = ??; 
     diff = stock - cursor->getAmount; 
     if(diff < 0){ 
      return false; 
     } 
    } 
    return true; 
} 

Oczywiście ta funkcja nie działa, ponieważ kursorem> GETPID() nie jest wykonywana, ponieważ jest ciągiem. Pytanie tutaj brzmi: jak wstawić zmienną C++ do kwerendy sql? W zwykłym C++ i użyłbym jakiejś funkcji swprintf_s. Czy dobry pomysł to także query.prepare(swprintf_s(...))?

Drugą rzeczą jest to, ponieważ zarówno query.exec() i query.prepare() są wartości logiczne, które zwracają prawdę lub fałsz, depeding na sukces, jaki sposób można przechowywać wyniki zapytań w języku C++ zmiennej?

Proszę zauważyć, że jestem nowy w SQL i SQL z Qt. Używam QT5. Próbowałem już przeczytać dokumentację dotyczącą klasy QSqlQuery, a jej funkcje, BindValue() i addBindValue(), wydają się interesujące. Jednak naprawdę nie rozumiem, jak działają.

Edit

Więc teraz mam minimalny przykładem, że jeszcze nie działa, mimo następstwie przyjętej odpowiedź. Jednak kompilator nie daje mi żadnych ostrzeżeń lub błędów:

void MainWindow::on_ButtonSQL_clicked() 
{ 
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); 
    db.setHostName("..."); 
    db.setDatabaseName("..."); 
    db.setUserName("..."); 
    db.setPassword("..."); 
    db.setPort(3306); 
    db.open(); 

    QMessageBox msgBox; 

    if (db.open()) { 
     msgBox.setText("It works :)"); 
     msgBox.exec(); 
    } 
    else { 
     msgBox.setText("No connection."); 
     msgBox.exec(); 
    } 

    QSqlQuery query(db); 

    // This query worked! 
    query.exec("INSERT INTO users (id, username, balance) VALUES(25, 'someName', 10000)");  

    // initialize someNumber to check later, whether it was processed correctly. 
    int id = 2, someNumber = 20; 
    query.prepare("SELECT stock FROM products WHERE id = :myid"); 
    query.bindValue(":myid", id); 
    query.exec(); 

    QString idValue = query.boundValue(0).toString(); 

    someNumber = query.value(0).toInt(); 
    msgBox.setText("The stock is: "+QString::number(someNumber)+"\nThe placeholder has the value: "+idValue); 
    msgBox.exec(); 
} 

Oczekiwany MsgBox ostatniego MsgBox brzmi:

The stock is: 100 
The placeholder value is: 2 

Wyjście rzeczywiście jest:

The stock is: 0 
The placeholder value is: 2 

Gdybym zamiast próbować wybierz ciąg (np. productName), powiedzmy z QString myProductName = query.value(0).toString() (i odpowiednie zmiany w kodzie), zwracany będzie pusty ciąg znaków.

** ROZWIĄZANE: ** Zobacz komentarz od Florisa w zaakceptowanej odpowiedzi. Brakowało mi query.next().

+1

FYI: Jeśli szukasz Qt równowartość ciąg formatowania podobna do 'swprintf_s', przejdź czytać dokumentację klasy' QString', zwłaszcza różne 'QString :: arg' funkcje. – RobbieE

+0

Dzięki za te informacje! – Alex

Odpowiedz

6

To jest dość prosta rzeczywiście:

QSqlQuery query; 
query.prepare("Select stock from products where id = :input"); 
query.bindValue(":input", cursor->getPid()); 
query.exec(); 

powiązać wartości do argumentu w ciąg. Argumenty są następujące: :name. Istnieje również pozycyjne wiązanie, które wiąże się w kolejności, w jakiej widzi?

QSqlQuery query; 
query.prepare("Select stock from products where id = ?"); 
// No need for an identifier 
query.bindValue(cursor->getPid()); 
query.exec(); 

iteracyjne rekordy uzyskane z zapytania można wykonać następujące czynności:

QSqlQuery query; 
query.prepare("SELECT stock FROM employee WHERE id = ?"); 
query.bindValue(cursor->getPid()); 
query.exec(); 

if (query.next()) { 
    int stock = query.value(0).toInt(); 
    // You could store the information you obtain here in a vector or something 
} 

Można również umieścić oświadczenie przygotować na zewnątrz pętli for. Jeśli jesteś zainteresowany iterowaniem wielu rekordów (z instrukcji select), możesz zastąpić instrukcję if instrukcją while.

chodzi QSqlQuery::next():

Pobiera następny rekord w rezultacie, jeśli są dostępne, i pozycjonuje zapytanie o pobranego rekordu. Należy pamiętać, że wynik musi być w stanie aktywnym i isSelect() musi zwracać wartość true przed wywołaniem tej funkcji czy będzie to nic nie robić i return false.

As taken from QSqlQuery. Trzeba będzie zrobić to wezwanie przed rekord rzeczywiście będzie dostępny z .value(int).

+0

Dziękuję za to dobrze napisane wyjaśnienie. Czy mógłbyś jednak spojrzeć na moją edycję? Wygląda na to, że jeszcze nie działa. – Alex

+0

@Alex Odpowiedź na to pytanie jest to, że zapomniał faktycznie wywołać następny wiersz (do odczytu). Uwaga ostatni przykład mam odpowiedź: 'if (query.next()) {int Grafika = query.value (0) .toInt(); } '. Pytanie o wartość bez zgłoszenia pierwszego wiersza wyniku nie daje właściwej odpowiedzi! Powinno działać, jeśli dodasz 'query.next()'. –

+1

Dzięki, teraz działa jak czar! :) – Alex

Powiązane problemy