2010-09-17 9 views
7

Tengo un archivo que contiene varias sentencias SQL que me gustaría utilizar para inicializar un nuevo archivo de base de datos sqlite3. Aparentemente, sqlite3 solo maneja múltiples declaraciones en una consulta a través de la función sqlite3_exec, y no a través de las funciones de preparación/paso/finalización. Eso está bien, pero me gustaría utilizar la API QtSQL en lugar de la API directamente. Al cargar en el mismo archivo de inicializador a través de QSqlQuery, solo se ejecuta la primera instrucción, al igual que al utilizar directamente las funciones de preparación/paso/finalización de la api sqlite3. ¿Hay alguna manera de hacer que QSqlQuery ejecute varias consultas sin tener que tener llamadas separadas a query.exec() para cada instrucción?sentencias SQL múltiples en QSqlQuery con el controlador sqlite3

Respuesta

9

Como se indica claramente en Qt Documentación para QSqlQuery::prepare() y QSqlQuery::exec(),

para SQLite, la cadena de consulta puede contener sólo una instrucción a la vez. Si se dan más de una instrucción, la función devuelve falso.

Como ya ha adivinado, la única solución conocida para esta limitación es tener todas las sentencias sql separadas por una cadena, dividir las instrucciones y ejecutar cada una de ellas en un bucle.

Vea el siguiente código de ejemplo (que usa ";" como separador y supone que no se usa el mismo carácter dentro de las consultas ... esto carece de generalidad, ya que puede tener el carácter dado en literales de cadena en donde/insert/instrucciones de actualización):

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

¿qué tal SELECT "hola, mundo de la tabla" 'o 'SELECT * FROM tabla --hello; world'? – yrHeTaTeJlb

1

yo escribimos una función simple para leer SQL desde un archivo y ejecutarlo una instrucción a la vez.

/** 
* @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(); 
     } 
    } 
} 
Cuestiones relacionadas