2009-11-26 79 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