У меня есть файл, содержащий несколько операторов sql, которые я хотел бы использовать для инициализации нового файла базы данных sqlite3. По-видимому, sqlite3 обрабатывает только несколько операторов в одном запросе через функцию sqlite3_exec, а не через функции подготовки/шага/завершения. Все в порядке, но я бы хотел использовать apt QtSQL, а не c api. Загрузка в тот же файл инициализатора через QSqlQuery выполняет только первый оператор, точно так же, как непосредственно с помощью функций prepare/step/finalize из sqlite3 api. Есть ли способ заставить QSqlQuery запускать несколько запросов без необходимости иметь отдельные вызовы query.exec() для каждого оператора?несколько операторов sql в QSqlQuery с использованием драйвера sqlite3
ответ
Как четко указано в Qt документации для QSqlQuery::prepare() и QSqlQuery::exec(),
Для SQLite, строка запроса может содержать только один оператор в то время. Если задано несколько операторов, функция возвращает false.
Как вы уже догадались, единственным известным обходным путем для этого ограничения является наличие всех операторов sql, разделенных некоторой строкой, разделение операторов и выполнение каждого из них в цикле.
См. Следующий примерный код (который использует «;» как разделитель и предполагает, что в запросах используется тот же символ, который не используется внутри этих запросов.Это не хватает общности, поскольку у вас может быть данный символ в строковых литералах, где/insert /):
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();
}
}
Я написал простую функцию для чтения 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();
}
}
}
как о 'SELECT "привет; мир из таблицы" или' SELECT * FROM таблицы --hello; world'? – yrHeTaTeJlb