Solved Problema con query e QSqlQuery prepare
-
ciao a tutti!
ho questa query in un file di testo.
se la eseguo dentro all'sqldeveloper funziona correttamente, mentre qui non estrae nulla:SELECT LT.DESCR128 DESCRIZIONE, LT.NUMERAT || LT.PERIODO || LPAD(LT.NUM, 6, '0') || LT.SERIE LISTINO, MA.CODINT ARTICOLO, LD.PRZDIVISA PREZZO, LD.SCONTO1 SCONTO1, LD.SCONTO2 SCONTO2, LD.SCONTO3 SCONTO3, LT.DAL DAL, LT.AL AL FROM LIST_OFF_DETT LD INNER JOIN MAT_ANAG MA ON MA.NPAM = LD.NPAM INNER JOIN LIST_OFF_TEST LT ON LT.NUMERAT = LD.NUMERAT AND LT.PERIODO = LD.PERIODO AND LT.NUM = LD.NUM AND LT.SERIE = LD.SERIE WHERE MA.DITMAT = 'XXL' AND MA.FVL = ' ' AND LT.DITTA = 'XXL' AND LT.FVL = ' ' AND LD.DITTA = 'XXL' AND LD.FVL = ' ' AND MA.CODINT = :articolo;
questo il codice:
if (db->isOpened()) { QFile queryFile(":/get_listini_articolo.txt"); queryFile.open(QFile::ReadOnly | QFile::Text); QByteArray ba = queryFile.readAll(); QString strQuery(QString::fromUtf8(ba)); strQuery.replace("\n", ""); QSqlQuery query; query.prepare(strQuery); query.bindValue(":articolo", this->articolo); query.exec(); qDebug() << query.lastError().text(); int rows = 0; while (query.next()) { ui->tblArticoli->insertRow(ui->tblArticoli->rowCount()); for (int i = 0; i < header.size(); ++i) { ui->tblArticoli->setItem(rows, i, new QTableWidgetItem(query.value(header.at(i)).toString())); } rows++; } query.clear(); }
se invece usassi il LIKE nella query, e mettessi il bindValue in questo modo, funzionerebbe:
query.bindValue(":articolo", this->articolo + "%");
sinceramente non capisco il perchè.
c'è un modo per visualizzare la query completo di parametro passato alla prepare?
oppure avete altre idee?? -
Prima di tutto quersto
QByteArray ba = queryFile.readAll(); QString strQuery(QString::fromUtf8(ba));
e' un incubo se cambi encoding o modo di scriver il newline. usa:
QString strQuery = QTextStream(&queryFile).readAll();
Prova a non mettere il
;
alla fine e vedi se va@fermatqt said in Problema con query e QSqlQuery prepare:
c'è un modo per visualizzare la query
-
ciao!
innanzitutto grazie per il suggerimento.
ho fatto subito la modifica con QTextStream.ho levato il ; finale, ma non cmq non ci sono record
ho messo questa riga:query.exec(); qDebug() << query.lastQuery(
il problema è che vedo questo:
"SELECT LT.DESCR128 DESCRIZIONE,LT.NUMERAT || LT.PERIODO || LPAD(LT.NUM, 6, '0') || LT.SERIE LISTINO,MA.CODINT ARTICOLO,LD.PRZDIVISA PREZZO,LD.SCONTO1 SCONTO1,LD.SCONTO2 SCONTO2,LD.SCONTO3 SCONTO3,LT.DAL DAL,LT.AL AL FROM LIST_OFF_DETT LD INNER JOIN MAT_ANAG MA ON MA.NPAM = LD.NPAM INNER JOIN LIST_OFF_TEST LT ON LT.NUMERAT = LD.NUMERAT AND LT.PERIODO = LD.PERIODO AND LT.NUM = LD.NUM AND LT.SERIE = LD.SERIE WHERE MA.DITMAT = 'XXL' AND MA.FVL = ' ' AND LT.DITTA = 'XXL' AND LT.FVL = ' ' AND LD.DITTA = 'XXL' AND LD.FVL = ' ' AND MA.CODINT = :articolo"
in sostanza non vedo che valore gli arriva!
-
per vedere i parametri usa http://doc.qt.io/qt-5/qsqlquery.html#boundValues
-
ok, allora mi sembra che il parametro arrivi:
QMapIterator<QString, QVariant> i(query.boundValues()); while (i.hasNext()) { i.next(); qDebug() << i.key().toUtf8().data() << ": " << i.value().toString().toUtf8().data() << endl; }
ho provato a mettere il parametro fisso così:
query.bindValue(":articolo", "C165-000");
ma non è cambiato nulla.
ovviamente se modifico la query in questo modo, funziona:SELECT LT.DESCR128 DESCRIZIONE, LT.NUMERAT || LT.PERIODO || LPAD(LT.NUM, 6, '0') || LT.SERIE LISTINO, MA.CODINT ARTICOLO, LD.PRZDIVISA PREZZO, LD.SCONTO1 SCONTO1, LD.SCONTO2 SCONTO2, LD.SCONTO3 SCONTO3, LT.DAL DAL, LT.AL AL FROM LIST_OFF_DETT LD INNER JOIN MAT_ANAG MA ON MA.NPAM = LD.NPAM INNER JOIN LIST_OFF_TEST LT ON LT.NUMERAT = LD.NUMERAT AND LT.PERIODO = LD.PERIODO AND LT.NUM = LD.NUM AND LT.SERIE = LD.SERIE WHERE MA.DITMAT = 'XXL' AND MA.FVL = ' ' AND LT.DITTA = 'XXL' AND LT.FVL = ' ' AND LD.DITTA = 'XXL' AND LD.FVL = ' ' AND MA.CODINT = 'C165-000'
quindi si comporta come se non gli arrivasse il parametro in sostanza!
-
dopo che hai eseguito la query senza succasso, puoi chiamare
qDebug() << query.lastError().text();
per vedere cosa succede? -
ciao.
ho modificato così:
if (db->isOpened()) { QFile queryFile(":/get_listini_articolo.txt"); queryFile.open(QFile::ReadOnly | QFile::Text); QString strQuery = QTextStream(&queryFile).readAll(); strQuery.replace("\n", ""); QSqlQuery query; query.prepare(strQuery); query.bindValue(":articolo", "C165-000"); query.exec(); QMapIterator<QString, QVariant> i(query.boundValues()); while (i.hasNext()) { i.next(); qDebug() << i.key().toUtf8().data() << ": " << i.value().toString().toUtf8().data() << endl; } int rows = 0; while (query.next()) { ui->tblArticoli->insertRow(ui->tblArticoli->rowCount()); for (int i = 0; i < header.size(); ++i) { ui->tblArticoli->setItem(rows, i, new QTableWidgetItem(query.value(header.at(i)).toString())); } rows++; } query.clear(); qDebug() << query.lastError().text(); }
come output mi esce questo:
:articolo : C165-000 " "
in sostanza non mostra nessun errore.
è come se gli arrivasse un parametro "sbagliato" e che non è in grado di leggere bene.
solo se metto l'uguale nella query, non se metto il LIKE. -
3 cose,
- prova a sostituire
query.exec();
conif(!query.exec()) Q_ASSERT(false);
- che tipo é
MA.CODINT
? int, nvarchar, etc. - controlla che, con un altro manager per DB riesci a vedere dati con quella query quando usi l'uguale
- prova a sostituire
-
ok, allora:
- ho messo così, me in output non dice nulla; quindi la query dovrebbe essere eseguita:
if (db->isOpened()) { QFile queryFile(":/get_listini_articolo.txt"); queryFile.open(QFile::ReadOnly | QFile::Text); QString strQuery = QTextStream(&queryFile).readAll(); strQuery.replace("\n", ""); QSqlQuery query; query.prepare(strQuery); query.bindValue(":articol", "C165-000"); //query.exec(); if(!query.exec()) Q_ASSERT(false); /*QMapIterator<QString, QVariant> i(query.boundValues()); while (i.hasNext()) { i.next(); qDebug() << i.key().toUtf8().data() << ": " << i.value().toString().toUtf8().data() << endl; } qDebug() << query.lastError().text();*/ int rows = 0; while (query.next()) { ui->tblArticoli->insertRow(ui->tblArticoli->rowCount()); for (int i = 0; i < header.size(); ++i) { ui->tblArticoli->setItem(rows, i, new QTableWidgetItem(query.value(header.at(i)).toString())); } rows++; } query.clear(); }
-
MA.CODINT è un VARCHAR; il db è ORACLE
-
se esguo la query su SQLDEVELOPER funziona correttamente; anzi, io le faccio sempre prima su SQLDEVELOPER in modo da scrivere query corrette ed evitare questi problemi; ed infatti è questo che mi lascia perplesso!
-
query.bindValue(":articol", "C165-000");
manca una o... typo?Sono abbastanza a corto di idee su cosa possa andare male, l'ultimo tentativo che ti chiederei e' usare positional binding cioe' sostituire
:articolo
nella query con?
e usarequery.bindValue(0, QStringLiteral("C165-000"));
-
articol era solo una prova...
cmq ho messo così:
query.bindValue(0, QStringLiteral("C165-000")); if(!query.exec()) Q_ASSERT(false);
e messo il ? nella query.
ma non estrae nulla.ti capisco, anche io sono a corto di idee!
-
allora, ho fatto la prova del 9.
ho scritto la query direttamente nel codice e levato il prepare:QString strQuery = "SELECT LT.DESCR128 DESCRIZIONE,LT.NUMERAT || LT.PERIODO || LPAD(LT.NUM, 6, '0') || LT.SERIE LISTINO,MA.CODINT ARTICOLO,LD.PRZDIVISA PREZZO,LD.SCONTO1 SCONTO1,LD.SCONTO2 SCONTO2,LD.SCONTO3 SCONTO3,LT.DAL DAL,LT.AL AL FROM LIST_OFF_DETT LD INNER JOIN MAT_ANAG MA ON MA.NPAM = LD.NPAM INNER JOIN LIST_OFF_TEST LT ON LT.NUMERAT = LD.NUMERAT AND LT.PERIODO = LD.PERIODO AND LT.NUM = LD.NUM AND LT.SERIE = LD.SERIE WHERE MA.DITMAT = 'XXL' AND MA.FVL = ' ' AND LT.DITTA = 'XXL' AND LT.FVL = ' ' AND LD.DITTA = 'XXL' AND LD.FVL = ' ' AND MA.CODINT = '" + this->articolo + "'"; QSqlQuery query; query.exec(strQuery);
così funziona, concatenando il singolo apice nella stringa del parametro.
potrebbe essere quello il problema??? -
purtroppo quella soluzione apre le porte dell'inferno chiamato SQL Injection quindi non e' accettabile.
prova a guardare cosa ti da in output:qDebug() << db->driver->hasFeature(QSqlDriver::PreparedQueries); qDebug() << db->driver->hasFeature(QSqlDriver::NamedPlaceholders); qDebug() << db->driver->hasFeature(QSqlDriver::PositionalPlaceholders);
se sono tutti true prova a usare bindValue con la query scritta nel codice e vedere se cosi' funziona
-
si ma infatti è solo una prova.
non ho intenzione di usare la query così!cmq QSqlDriver::NamedPlaceholders mi da false, gli altri true.
quindi suppongo debba sempre usare ? e non :articoli.
se così, ho provato in questo modo:QString strQuery = "SELECT LT.DESCR128 DESCRIZIONE,LT.NUMERAT || LT.PERIODO || LPAD(LT.NUM, 6, '0') || LT.SERIE LISTINO,MA.CODINT ARTICOLO,LD.PRZDIVISA PREZZO,LD.SCONTO1 SCONTO1,LD.SCONTO2 SCONTO2,LD.SCONTO3 SCONTO3,LT.DAL DAL,LT.AL AL FROM LIST_OFF_DETT LD INNER JOIN MAT_ANAG MA ON MA.NPAM = LD.NPAM INNER JOIN LIST_OFF_TEST LT ON LT.NUMERAT = LD.NUMERAT AND LT.PERIODO = LD.PERIODO AND LT.NUM = LD.NUM AND LT.SERIE = LD.SERIE WHERE MA.DITMAT = 'XXL' AND MA.FVL = ' ' AND LT.DITTA = 'XXL' AND LT.FVL = ' ' AND LD.DITTA = 'XXL' AND LD.FVL = ' ' AND MA.CODINT = '?'"; QSqlQuery query; query.prepare(strQuery); query.bindValue(0, this->articolo); query.exec();
ma continuo ad avere zero record.
-
'?'
questo e' sbagliato, non devi mettere gli apostrofi, solo il?
@fermatqt said in Problema con query e QSqlQuery prepare:
quindi suppongo debba sempre usare ? e non :articoli.
corretto!
-
si quella con '?' era una prova.
cmq ho provato sia così:QString strQuery = ".............. MA.CODINT = ?"; QSqlQuery query; query.prepare(strQuery); query.addBindValue("C165-000");
che così:
QString strQuery = "........... MA.CODINT = ?"; QSqlQuery query; query.prepare(strQuery); query.bindValue(0, this->articolo);
non è che debba specificare di che tipo è il bindValue??
-
no, se
this->articolo
e' QString il tipo viene dedotto in automatico, devi specificare il tipo solo se vuoi passare l'equivalente di NULLproviamo con una query base:
QSqlQuery query; query.prepare("select * from MAT_ANAG where CODINT = ?"); query.bindValue(0, "C165-000"); if(query.exec()) { while(query.next()){ qDebug() << query.record().value("CODINT"); } } else{ qDebug() << query.lastError().text(); }
e dimmi se ti da risultati
-
ecco il codice:
qDebug() << "STARTED"; if (db->isOpened()) { QSqlQuery query; query.prepare("SELECT * FROM MAT_ANAG WHERE CODINT = ?"); query.bindValue(0, "C165-000"); if (query.exec()) { while (query.next()) { qDebug() << "CODINT: " << query.record().value("CODINT"); } } else { qDebug() << query.lastError().text(); } } else { qDebug() << "DB chiuso"; } qDebug() << "FINISHED";
una volta lanciato, il programma lavora per circa 5 secondi.
quindi penso voglia dire che la query la sta eseguendo
ma l'output è solo questo:STARTED FINISHED
inoltre, se scrivessi una query appositamente errata (ad esempio SELEC e non SELECT) vedrei l'errore in console.
quindi anche la query dovrebbe essere giusta.infine se uso il LIKE funziona:
qDebug() << "STARTED"; if (db->isOpened()) { QSqlQuery query; query.prepare("SELECT * FROM MAT_ANAG WHERE CODINT LIKE ?"); query.bindValue(0, "C165-000%"); if (query.exec()) { while (query.next()) { qDebug() << "CODINT: " << query.record().value("CODINT"); } } else { qDebug() << query.lastError().text(); } } else { qDebug() << "DB chiuso"; } qDebug() << "FINISHED";
-
a questo punto sono convinto che il problema sia nei dati, non nella query.
Prova una cosa. usa la query con il like ma sostituisci
qDebug() << "CODINT: " << query.record().value("CODINT");
conqDebug() << "CODINT: " << query.record().value("CODINT").toString().size();
se stampa 8 mi bevo un'intera bottiglia di vodka in un sol fiato! -
purtroppo niente vodka, ti avrei fatto volentieri compagni con il gin!
questo il codice:
qDebug() << "STARTED"; if (db->isOpened()) { QSqlQuery query; query.prepare("SELECT * FROM MAT_ANAG WHERE CODINT LIKE ?"); query.bindValue(0, "C165-000%"); if (query.exec()) { while (query.next()) { qDebug() << "CODINT: " << query.record().value("CODINT").toString().size(); } } else { qDebug() << query.lastError().text(); } } else { qDebug() << "DB chiuso"; } qDebug() << "FINISHED";
questo l'output:
STARTED CODINT: 30 CODINT: 30 CODINT: 30 CODINT: 30 .................... FINISHED
ho controllato sul db il tipo di campo:
CODINT NOT NULL CHAR(30)