使用sqlite3_exec

时间:2009-11-26 22:39:18

标签: c sqlite

我有下一个SQLITE3命令,它生成一个包含超过6000万条记录的文件:

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

如何使用以下命令将这些命令包含到C程序中:

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

当我自己尝试这样做时,c程序在执行时会产生表达式错误。

谢谢!

4 个答案:

答案 0 :(得分:8)

如果你想在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;
}

答案 1 :(得分:3)

我认为你真的希望use a callback function和fprintf()将格式化的输出写入文件。幸运的是,回调指针的原型包含一个额外的(可选的)void *,它可以作为FILE *流,使得回调在将来更容易重复使用。

AFAIK,sqlite3_exec()不提供与sqlite3 CLI相同的界面。它仅用于查询,而不是输出修饰符。

查看我给出的链接底部的示例代码,它非常容易使用回调函数。

答案 2 :(得分:3)

本书Using SQLite的配套网站有一些例子。特别是,第7章有一些C / C ++ API的例子。

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

答案 3 :(得分:2)

我正在使用包含char字符串键和单个整数值的单个表,使用简单的测试工具对SQLite进行一些实验。以下是我正在使用的实验测试工具的来源。我提取这些部分是为了显示表的创建以及我用来使用SQLite的回调功能从select 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;
}

处理select返回的每条记录的回调如下所示:

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