2009-11-26 7 views
9

Ich habe die nächsten Sqlite3 Befehle, die eine Datei mit mehr als 60 Millionen Datensätze erzeugt:Verwendung von sqlite3_exec

.mode csv 
.output matppp.csv 
select mat, ppp from matppp order by mat; 
.output stdout 

Wie kann ich diese Befehle in einem C-Programm schließen ein:

sqlite3_exec(db, "..........", NULL, 0, &db_err); 

?

Wenn ich versuche, es selbst zu tun, erzeugt das Programm c einen Ausdruck Fehler beim Ausführen.

Danke !!

+0

Definieren eines Rückrufs zum Formatieren und Ausdrucken wie gewünscht ist keine Option? –

Antwort

7

Wenn Sie dies in C tun wollen (im Gegensatz zu etwas an sqlite3's Kommandozeilenprogramm, das diese geschickten Punktbefehle hat), dann müssen Sie einen Rückruf verwenden.

Für Ihre Bequemlichkeit beim Schneiden und Einfügen, hier ist der Code, gehackt aus der Apophienia-Bibliothek für statistische Berechnungen.

Teil I:

sqlite3 *db=NULL; //The global database handle. 

static int apop_db_open(char *filename){ 
    if (!filename) 
     sqlite3_open(":memory:",&db); 
    else    
     sqlite3_open(filename,&db); 
    if (!db) 
     printf("Not sure why, but the database didn't open.\n"); 
    return 0; 
} 

//From the SQLite manual: 
#define ERRCHECK {if (err!=NULL) {printf("%s\n",err); sqlite3_free(err); return 0;}} 

apop_data * apop_sqlite_query_to_screen(char *query){ 
    char *err = NULL; 
    if (db==NULL) 
     apop_db_open(NULL); 
    sqlite3_exec(db, query, The_Callback, a_param, &err); 
    ERRCHECK 
} 

Teil II:

Der Rückruf wird die folgende Form haben, und wird einmal für jede Zeile zurückgegeben. Beachten Sie, wie der Parameter a_param überträgt; Wenn Sie es nicht benötigen (wie in diesem Beispiel), setzen Sie es einfach auf NULL oben.

+2

Wenn Sie einen Fehler erhalten, sollten Sie es ausdrucken, dann befreien Sie es mit sqlite3_free (err); –

3

Ich denke, Sie möchten wirklich use a callback function und vielleicht fprintf() Ihre formatierte Ausgabe in eine Datei schreiben. Glücklicherweise enthält der Prototyp für den Callback-Zeiger ein zusätzliches (optionales) void *, das als FILE * -Stream dienen könnte, wodurch der Callback in Zukunft wiederverwendbar wird.

AFAIK, sqlite3_exec() bietet nicht dieselbe Schnittstelle wie sqlite3 CLI. Es ist nur für Abfragen, nicht Ausgabe Modifikatoren.

Überprüfen Sie den Beispielcode am unteren Rand der Verbindung, die ich gab, es ist sehr einfach, eine Rückruffunktion zu verwenden.

2

Die begleitende Website des Buches Using SQLite hat einige Beispiele. Insbesondere enthält Kapitel 7 einige Beispiele für die C/C++ - API.

Beispielcode: http://examples.oreilly.com/9780596521196/

+0

Der Buchlink ist umgezogen. Hier ist eine Suche, die zwei O'Reilly-Bücher auf SQLite zeigt http://search.oreilly.com/?q=sqlite&x=-759&y=-56 Es sieht so aus, als ob der Beispielcode immer noch unter dem obigen Link ist. –

2

Ich mache einige Experimente mit SQLite mit einem einfachen Test-Harnisch eine einzelne Tabelle verwenden, die ein char String-Schlüssel und ein einzelner Integer-Wert enthält. Das Folgende sind Teile der Quelle aus dem experimentellen Test Kabelbaum, den ich verwende. Ich habe diese Teile gezogen, um die Erstellung der Tabelle zusammen mit der Funktion zu zeigen, die ich benutze, um eine Datensatzmenge aus einer SELECT-SQL-Anweisung mit der Rückruffunktion von SQLite zu erstellen. Es gibt printf() Anweisungen und fprintf() Anweisungen an verschiedenen Stellen, so dass ich die Ergebnisse von Aktionen sehen kann, da dies eine einfache Konsolanwendung für den Testkabelbaum ist.

Beachten Sie, dass es Zeiten gibt, in denen Sie das Argument Rückruf nicht benötigen, so dass SQLite Ihnen ermöglicht, einen Nullzeiger anzugeben, der angibt, dass der Rückruf nicht gestört wird.

Und wie Sie über die Quelle lesen, denken Sie daran, dies ist ein experimenteller Hack!

Die Funktion zum Erstellen der Tabelle wie folgt aussieht:

int CreateSetupTable (sqlite3 *db) 
{ 
    char *zErrMsg = 0; 
    int rc; 
    char *aszSqlCreate = "create table tbl1(one varchar(10), two smallint)"; 
    char *aszSqlCreateIndex01 = "create unique index index1 on tbl1 (one)"; 

    do { 
     rc = sqlite3_exec(db, aszSqlCreate, 0, 0, &zErrMsg); 
     if(rc!=SQLITE_OK){ 
      fprintf(stderr, "SQL error: %s\n", zErrMsg); 
      sqlite3_free(zErrMsg); 
      break; 
     } 

     rc = sqlite3_exec(db, aszSqlCreateIndex01, 0, 0, &zErrMsg); 
     if(rc!=SQLITE_OK){ 
      fprintf(stderr, "SQL error: %s\n", zErrMsg); 
      sqlite3_free(zErrMsg); 
      break; 
     } 
    } while (0); // loop only once to allow breaks on errors 

    return rc; 
} 

ich einige Datensätze in diese Tabelle einfügen und dann eine Funktion, die ich eine oder mehr Datensätze aus der Tabelle eine ausgewählte SQL-Anweisung erhalten rufen. Die Auswahlfunktion ruft die Datensätze ab und verwendet einen Rückruf, um jeden zurückgegebenen Datensatz in eine C-Struktur umzuwandeln. Die C-Struktur wie folgt aussehen:

typedef struct { 
    char cKey[20]; 
    int iValue; 
} Tbl1Record; 

Der Aufruf für den Datensatz verwendet zurück verwendet eine Struktur, die Aufzeichnung wählen Sie Verwaltungsdaten enthält. Damit meine ich, dass der Rückruf als erstes Argument einen Zeiger auf eine Struktur verwendet, die wiederum auf die Stelle verweist, an der die transformierten Daten zusammen mit einigen Informationen über die Größe des Speicherbereichs abgelegt werden. Da eine Auswahl abhängig von der where-Klausel mehr als einen Datensatz zurückgeben kann, verwendet die Rückruffunktion die Rückrufstruktur, um zu ermitteln, wie viele transformierte Datensätze in den Speicherbereich eingefügt werden können, sowie einen Index, so dass beim Erstellen von Datensätzen Es kann durch den Speicherbereich indizieren, um mehrere transformierte Datensätze zurückzugeben.

Der Rückruf sieht Management-Struktur wie folgt aus:

typedef struct _RecordProcessor { 
    void *pRecordSet; 
    int nRecordSetMax; 
    int nRecordSetActual; 
} RecordProcessor; 

Die select-Funktion wie folgt aussieht:

int SelectRecord (sqlite3 *db, char *cSelect, char *cKey) 
{ 
    char *zErrMsg = 0; 
    int rc; 
    char aszSqlSelect[128]; 
    Tbl1Record myRec[20]; 
    RecordProcessor myProcessor; 

    myProcessor.pRecordSet = myRec; 
    myProcessor.nRecordSetActual = 0; 
    myProcessor.nRecordSetMax = 20; 

    if (cKey) { 
     sprintf (aszSqlSelect, "select %s from tbl1 where one='%s'", cSelect, cKey); 
    } else { 
     sprintf (aszSqlSelect, "select %s from tbl1", cSelect); 
    } 
    rc = sqlite3_exec(db, aszSqlSelect, MyRecordProcessor, &myProcessor, &zErrMsg); 
    if(rc!=SQLITE_OK){ 
     fprintf(stderr, "SQL error SelectRecord: %s\n", zErrMsg); 
     sqlite3_free(zErrMsg); 
    } else { 
     int i; 
     for (i = 0; i < myProcessor.nRecordSetActual; i++) { 
      printf ("ReC#%d cKey = %s iValue = %d\n", i+1, myRec[i].cKey, myRec[i].iValue); 
     } 
    } 

    return rc; 
} 

Der Rückruf, die jeden Datensatz durch die Auswahl sieht wie folgt zurück verarbeitet:

static int MyRecordProcessor (void *callBackArg, int argc, char **argv, char **azColName) 
{ 
    int iRetStatus = 0; 
    char *colNameTable[] = { 
     "one", 
     "two" 
    }; 
    Tbl1Record *pTbl1Record = (Tbl1Record *)((RecordProcessor *)callBackArg)->pRecordSet; 

    if (((RecordProcessor *)callBackArg)->nRecordSetActual < ((RecordProcessor *)callBackArg)->nRecordSetMax) { 
     int i, j; 
     int iIndex = ((RecordProcessor *)callBackArg)->nRecordSetActual; 

     memset (pTbl1Record + iIndex, 0, sizeof(Tbl1Record)); 
     ((RecordProcessor *)callBackArg)->nRecordSetActual++; 
     for (i = 0; i < argc; i++){ 
      int j; 
      for (j = 0; j < sizeof (colNameTable)/sizeof(colNameTable[0]); j++) { 
       if (strcmp (azColName[i], colNameTable[j]) == 0) { 
        switch (j) { 
         case 0: 
          strncpy (pTbl1Record[iIndex].cKey, (argv[i] ? argv[i] : "NULL"), 19); 
          break; 
         case 1: 
          pTbl1Record[iIndex].iValue = atoi (argv[i] ? argv[i] : "0"); 
          break; 
         default: 
          break; 
        } 
        break; 
       } 
      } 
     } 
    } 

    return iRetStatus; 
} 
+0

Ist das eine Antwort auf die Frage? Es scheint ein wenig komplex als Beispiel, und gibt nicht als CSV (wie der Fragesteller scheint zu wollen) – Hasturkun

+0

@Hasturkun, fand ich dies durch eine Google-Suche während der Untersuchung, wie SQLite zu verwenden. Ich habe dieses Beispiel aus meinen eigenen Untersuchungen hier zitiert, weil die Frage war, sqlite3_exec() zu verwenden, damit andere es ebenfalls nützlich finden. Manchmal hilft eine allgemeinere Antwort Leuten, die die Frage durch google suchen, aber die Antworten sind zu spezifisch, um zu helfen. Ich entschloss mich, weitere Einzelheiten über die Verwendung eines Rückrufs anzugeben. –

+0

@RichardChambers danke! Das ist, was ich gesucht habe. – aepryus

Verwandte Themen