несколько операторов SQL в QSqlQuery с использованием драйвера sqlite3 - PullRequest
8 голосов
/ 17 сентября 2010

У меня есть файл, содержащий несколько операторов SQL, которые я хотел бы использовать для инициализации нового файла базы данных sqlite3. Очевидно, sqlite3 обрабатывает только несколько операторов в одном запросе через функцию sqlite3_exec(), а не - через функции prepare/step/finalize. Это все нормально, но я бы хотел использовать API QtSQL, а не API. Загрузка в тот же файл инициализатора через QSqlQuery выполняет только первый оператор, точно так же, как непосредственно с использованием функций prepare / step / finalize из API sqlite3. Есть ли способ заставить QSqlQuery выполнять несколько запросов без необходимости отдельных вызовов query.exec () для каждого оператора?

Ответы [ 2 ]

11 голосов
/ 30 января 2012

Как четко указано в документации Qt для QSqlQuery :: prepare () и QSqlQuery :: exec () ,

Для SQLite запросСтрока может содержать только одну инструкцию за раз.Если дано более одного оператора, функция возвращает false.

Как вы уже догадались, единственный известный обходной путь к этому ограничению состоит в том, чтобы все операторы sql были разделены некоторой строкой, разделить операторы и выполнитькаждый из них в цикле.

См. следующий пример кода (который использует ";" в качестве разделителя и предполагает, что тот же символ не используется в запросах ... в этом не хватает универсальности, поскольку вы можете иметьсимвол в строковых литералах в операторах where / insert / update):

QSqlDatabase database;
QSqlQuery query(database);
QFile scriptFile("/path/to/your/script.sql");
if (scriptFile.open(QIODevice::ReadOnly))
{
    // The SQLite driver executes only a single (the first) query in the QSqlQuery
    //  if the script contains more queries, it needs to be splitted.
    QStringList scriptQueries = QTextStream(&scriptFile).readAll().split(';');

    foreach (QString queryTxt, scriptQueries)
    {
        if (queryTxt.trimmed().isEmpty()) {
            continue;
        }
        if (!query.exec(queryTxt))
        {
            qFatal(QString("One of the query failed to execute."
                        " Error detail: " + query.lastError().text()).toLocal8Bit());
        }
        query.finish();
    }
}
1 голос
/ 06 октября 2013

Я написал простую функцию для чтения SQL из файла и выполнения его по одному выражению за раз.

/**
* @brief executeQueriesFromFile Read each line from a .sql QFile
* (assumed to not have been opened before this function), and when ; is reached, execute
* the SQL gathered until then on the query object. Then do this until a COMMIT SQL
* statement is found. In other words, this function assumes each file is a single
* SQL transaction, ending with a COMMIT line.
*/

void executeQueriesFromFile(QFile *file, QSqlQuery *query)
{
    while (!file->atEnd()){
        QByteArray readLine="";
        QString cleanedLine;
        QString line="";
        bool finished=false;
        while(!finished){
            readLine = file->readLine();
            cleanedLine=readLine.trimmed();
            // remove comments at end of line
            QStringList strings=cleanedLine.split("--");
            cleanedLine=strings.at(0);

            // remove lines with only comment, and DROP lines
            if(!cleanedLine.startsWith("--")
                    && !cleanedLine.startsWith("DROP")
                    && !cleanedLine.isEmpty()){
                line+=cleanedLine;
            }
            if(cleanedLine.endsWith(";")){
                break;
            }
            if(cleanedLine.startsWith("COMMIT")){
                finished=true;
            }
        }

        if(!line.isEmpty()){
            query->exec(line);
        }
        if(!query->isActive()){
            qDebug() << QSqlDatabase::drivers();
            qDebug() <<  query->lastError();
            qDebug() << "test executed query:"<< query->executedQuery();
            qDebug() << "test last query:"<< query->lastQuery();
        }
    }
}
...