2009-11-26 34 views
9

我有一個生成與超過60萬條記錄文件的下一個SQLITE3命令:使用sqlite3_exec

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

我怎麼能包括這些命令將使用C程序:

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

當我嘗試自己做這件事時,c程序在執行時會生成一個表達式錯誤。

謝謝!

+0

定義回調以根據需要格式化並打印它不是一個選項嗎? – 2009-11-27 01:38:13

回答

7

如果你想C之內做到這一點(而不是管道的東西有那些漂亮點命令的sqlite3的命令行程序),那麼你將不得不使用一個回調。

爲了便於剪切和粘貼,下面是代碼,從Apophenia庫中進行統計計算。

第一部分:

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 
} 

第二部分:

回調將有以下形式,並運行一次,每行返回。注意參數a_param是如何傳遞的;如果你不需要它(如在這個例子中),只需將它設置爲NULL即可。

int The_Callback(void *a_param, int argc, char **argv, char **column){ 
    for (int i=0; i< argc; i++) 
     printf("%s,\t", argv[i]); 
    printf("\n"); 
    return 0; 
} 
+2

如果你得到一個錯誤,你應該打印它,然後用sqlite3_free(err)釋放它; – 2016-01-06 08:23:14

3

我想你真的想要use a callback function,也許fprintf()將你的格式化輸出寫入文件。幸運的是,回調指針的原型包含一個額外的(可選的)void *,它可以用作FILE *流,使回調在將來更加可重用。

AFAIK,sqlite3_exec()不提供與sqlite3 CLI相同的接口。它僅用於查詢,而不是輸出修飾符。

查看我給出的鏈接底部的示例代碼,它非常易於使用回調函數。

2

Using SQLite的同伴網站有一些例子。特別是,第7章有一些C/C++ API的例子。

示例代碼:http://examples.oreilly.com/9780596521196/

+0

書鏈接已移動。這裏是一個搜索,顯示兩本關於SQLite http://search.oreilly.com/?q=sqlite&x=-759&y=-56的O'Reilly書籍,它看起來像示例代碼仍然在上面的鏈接。 – 2013-06-06 13:43:01

2

我使用一個包含字符字符串鍵和一個整數值單個表做一些實驗中使用SQLite用一個簡單的測試工具。以下是我正在使用的實驗測試工具的源代碼片段。爲了顯示錶的創建以及我用來使用SQLite的回調函數從選擇SQL語句創建記錄集的功能,我將這些部分拉出來。在各個地方有printf()語句和fprintf()語句,以便我可以看到操作的結果,因爲這是測試工具的簡單控制檯類型應用程序。

注意,有些時候你不需要回調參數,因此SQLite的允許您指定表示不與呼叫懶得回NULL指針。

而當你閱讀源代碼時,請記住這是一個實驗性的黑客!

的函數來創建表如下所示:

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; 
} 

我插入一些記錄到這個表,然後讓我打電話使用select SQL語句來從表中的一個或多個記錄的功能。 select函數檢索記錄並使用回調將每個返回的記錄轉換爲C結構。 C結構如下所示:

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

用於記錄集的回調使用包含記錄選擇管理數據的結構。我的意思是,回調函數將第一個參數作爲指向結構體的指針,該結構體指向將轉換後的數據以及關於存儲區大小的一些信息的位置。由於select可能會根據where子句返回多個記錄,因此回調函數使用回調結構來知道可以將多少個轉換記錄放入內存區域以及索引,以便在放入記錄時,它可以通過內存區域索引以返回多個轉換記錄。

回叫管理結構是這樣的:

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

select函數看起來像:

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; 
} 

處理由選擇這個樣子的返回每條記錄的回電:

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

這是問題的答案嗎?它看起來有點複雜,並且不會像CSV那樣輸出(asker似乎想要的) – Hasturkun 2013-06-06 14:55:07

+0

@Hasturkun,我在調查如何使用SQLite時通過谷歌搜索發現了這一點。我把這個例子放在我自己的調查中,因爲問題是關於使用sqlite3_exec(),以便其他人也可能會覺得它很有用。有時候,一個更普通的答案可以幫助那些通過谷歌搜索發現問題的人,但是答案太具體,無法幫助。我決定提供有關使用回撥的更多詳細信息。 – 2013-06-06 15:30:30

+0

@RichardChambers謝謝!這是我正在尋找的。 – aepryus 2015-10-22 09:09:22

相關問題