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

    http://doc.qt.io/qt-5/qsqlquery.html#lastQuery



  • 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!





  • 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,

    1. prova a sostituire query.exec(); con if(!query.exec()) Q_ASSERT(false);
    2. che tipo é MA.CODINT? int, nvarchar, etc.
    3. controlla che, con un altro manager per DB riesci a vedere dati con quella query quando usi l'uguale


  • ok, allora:

    1. 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();
            }
    
    1. MA.CODINT è un VARCHAR; il db è ORACLE

    2. 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 usare query.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 NULL

    proviamo 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");
    con qDebug() << "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)



  • @fermatqt said in Problema con query e QSqlQuery prepare:

    MA.CODINT è un VARCHAR

    Mi hai mentito! :)

    quindi SELECT TRIM(CODINT) tc FROM MAT_ANAG WHERE tc = ? dovrebbe funzionare



  • scusa ero sicuro che fosse un VARCHAR!!
    ma più che altro su mysql non mi sembra di riscontrare questo comportamento che ho su oracle (ma magari mi sbaglio).

    cmq col TRIM funziona.

    grazie mille, ti devo una bottiglia di vodka!!



  • Nessun problem, felice che si sia risolto


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.