多列转为一列的SQL语句查询并对获取数据解析
项目开发中,需要从数据库查询数据,在不使用数据库库函数的情况下对获取的数据解析,
这时就可以对查询的SQL语句操作,使其要查询的每一项通过连接符连接在一起成为一项查询,
这时通过查询获取的数据就是一列的数据--一个字符串,再对字符串操作获取对应的每一项数据。
在编程实现中,可以把对SQL语句的操作看着是对字符串的操作,获取的结果也是看做字符串解析。
下面是简单实现,
环境:linux,oracle数据库,OCILIB库
[mw_shl_code=c,true]代码实现:
/*存放每一行数据的结构体*/
typedef struct _resultdata
{
int num;
int row_len;
SB1 *row_data;
struct _resultdata *next;
}ResultData;
/***********************************************************
*function:rs_link_insert
*description:
* 查询数据链表插入,将新的查询数据放进链表中
*input: head:链表头
* pi: 将要插进的新结点
*
*output: ResultData * :返回ResultData *指针,一般是链表
*头结点
* ********************************************************/
ResultData *rs_link_insert(ResultData *head,ResultData *pi)
{
ResultData *pb = NULL;
pb = head;
//链表为空时,创建链表
if(NULL == pb)
{
pb = pi;
pi->next = NULL;
head = pb;
//rs_tail = pi;
return head;
}
//不为空时,找到尾结点,并判断是否为空,为空将新结点
//插入当前尾结点后
//然后将新节点作为尾结点
while(pb->next)
{
//pf = pb;
pb = pb->next;
}
pb->next = pi;
pi->next = NULL;
return head;
}
/***********************************
*function: sql_format_deal
*description:
* 将源字符串中’,‘替换为“||chr(1)||”
*input: source:源字符串
* search:格式化后的字符串
*
*output: 列值
* ********************************/
int sql_format_deal(char* csource_ext,char *cresult)
{
int iwork_bgn = 0;//单词标示
int ibracket = 0;//括号标志
int icol_cnt = 1;//列值
char *csource = (char *)malloc(strlen(csource_ext) + 64);
char *csrc = csource;
char *cres = cresult;
strcpy(csource, csource_ext);
for(iwork_bgn=1,ibracket=0;*csrc;csrc++)
{
//如果到了from处,则不再替换
if((!strncasecmp(csrc,"from",4))&&iwork_bgn)
{
if(csrc[4]==0 || strchr(" \t\r\n",csrc[4]))
{
break;
}
}
//将csrc中‘,’替换为“||chr(1)||”,注:括号内不处理
if(!ibracket && *csrc == ',')
{
// 一个逗号则替换为||chr(1)||,两个逗号作为一个逗号(说明要单作为1列处理)
if(csrc[1]==',')
{
// 保存当前逗号,跳过pi[1]的逗号
*cres++ = *csrc++;
icol_cnt++;
}
else
{
//strcpy(cres,"||chr(1)||");
strcpy(cres,"||chr(1)||");
cres += strlen(cres);//是"||chr(1)||"的长度
}
}
else
{
*cres++ = *csrc;
// 判断是否一个词的开始
iwork_bgn = strchr(" \t\r\n",*csrc)?1:0;
// 判断是否在括号内
if('(' == *csrc)
{
ibracket++;
}
if(')' == *csrc)
{
ibracket--;
}
}
}
// from后面的内容全部拷贝
for(;*csrc;csrc++)
{
*cres++ = *csrc;
}
*cres = '\0';
free(csource);
return icol_cnt;
}
/***********************************
*function: db_select_data
*description:
* 查询SQL语句,获得查询数据,将数据存放在rs_data内
*
*
*input: CN:数据路连接对象
* SQL:SQL执行语句
* *row_num:查询数据行数
* rs_data:存放查询后的数据`
*
*output: >=0:sucess <0:fail
*注意:开辟了rs_data及rs_link链表内存空间
* 同时释放了sele_data及se_link链表内存空间
* rs_data及rs_link内存空间由函数
* db_get_le_data释放
*
* 开辟了format_sql空间,并在用完后释放
* ********************************/
int db_select_data(OCI_Connection *cn, char* sql,int *row_num,ResultData **rs_data)
{
OCI_Statement *st = NULL;
OCI_Resultset *rs = NULL;
int icolmn_cnt = 0;
int icnt = 0;
ResultData *pb_data = NULL;
ResultData *rs_head = NULL;
ResultData *rs_node = NULL;
int isql_len = 0;
SB1 *format_sql = NULL;
SB1 *ptemp = NULL;
SB1 *p1temp = NULL;
SB1 buf_data[MAX_ROW_LENGTH];
SB1 *pbuf_data = NULL;
int itemp1 = 0;
//char *ptmp = 0;
//对SQL语句断言
assert(sql);
//判断数据库连接对象是否为空
if(NULL == cn)
{
zlog_error(fzs_lib_mod_log,"---no connect to oracle,please check connect");
return -1;
}
pthread_mutex_lock(&mutex_cn);
//zlog_error(fzs_lib_mod_log,"cn addr:%p",cn);
//通过数据库连接对象获得SQL语句执行对象
st = OCI_StatementCreate(cn);
if(NULL == st)
{
//printf("file:%s---line:%d---OCI_StatementCreate---fail\r\n",POS_INFO);
zlog_error(fzs_lib_mod_log,"---OCI_StatementCreate---fail");
OCI_err_handler(OCI_GetLastError());
pthread_mutex_unlock(&mutex_cn);
return -1;
}
//sql格式化后的结构
isql_len = strlen(sql)+1024;
//分配内存空间
format_sql = (SB1*)malloc(isql_len);
memset(format_sql,0,isql_len);
//格式化SQL语句
icolmn_cnt = sql_format_deal(sql,format_sql);//多列的话目前没有处理
//printf("file:%s---line:%d-format_sql=%s\r\n",POS_INFO,format_sql);
zlog_debug(fzs_lib_mod_log,"-format_sql=%s",format_sql);
//printf("file:%s---line:%d-icolmn_cnt=%d\r\n",POS_INFO,icolmn_cnt);
zlog_debug(fzs_lib_mod_log,"-icolmn_cnt=%d",icolmn_cnt);
//执行SQL语句
if(!OCI_ExecuteStmt(st,format_sql))// format_sql 是格式化后的语句
{
zlog_error(fzs_lib_mod_log,"-OCI_ExecuteStmt---fail");
OCI_err_handler(OCI_GetLastError());
pthread_mutex_unlock(&mutex_cn);
return -1;
}
//获取结果集对象
zlog_debug(fzs_lib_mod_log,"-OCI_ExecuteStmt---OK!!!");
rs = OCI_GetResultset(st);
if(NULL == rs)
{
zlog_error(fzs_lib_mod_log,"OCI_ExecuteStmt---fail");
OCI_err_handler(OCI_GetLastError());
pthread_mutex_unlock(&mutex_cn);
return -1;
}
//对rs结果集中的数据处理,将rs数据存到rs_link中,并获得每行数据长度
while(OCI_FetchNext(rs))
{
icnt++;
//每次获得数据前,清空buf内数据
//printf("%s\n",OCI_GetString(rs,1));
memset(buf_data,0,MAX_ROW_LENGTH);
pbuf_data = buf_data;
for(itemp1 = 0; itemp1 < icolmn_cnt; itemp1++)
{
pbuf_data += strlen(pbuf_data);
if(itemp1 > 0)
*pbuf_data++ = 0x01;
sprintf(pbuf_data, OCI_GetString(rs, itemp1 + 1));
}
//printf("file:%s--line:%d--buf_data=%s\r\n",POS_INFO,buf_data);
zlog_debug(fzs_lib_mod_log,"--buf_data=%s",buf_data);
//irow_len = strlen(buf_data)+1;
//printf("file:%s--line:%d--*len=%d\r\n",POS_INFO,*len);
//zlog_debug(fzs_lib_mod_log,"*len=%d",*len);
//给pb_data分配内存空间
pb_data = (ResultData*)malloc(sizeof(ResultData));
//分配内存失败
if(pb_data == NULL)
{
//printf("SelectData--pb_data malloc memory fail\r\n");
zlog_error(fzs_lib_mod_log,"OCI_ExecuteStmt---fail");
//释放返回集
if(rs)
{
OCI_ReleaseResultsets(st);
//printf("file:%s--line:%d--OCI_ReleaseResultsets(st) success\r\n",POS_INFO);
}
//清除声明
if(st)
{
OCI_StatementFree(st);
//printf("file:%s--line:%d--OCI_StatementFree(st) success\r\n",POS_INFO);
}
pthread_mutex_unlock(&mutex_cn);
return -1;
}
pb_data->row_data = (SB1*)malloc((strlen(buf_data)+1));
//分配内存失败
if(pb_data->row_data == NULL)
{
//printf("SelectData--pb_data->row_data malloc memory fail\r\n");
zlog_error(fzs_lib_mod_log,"SelectData--pb_data->row_data malloc memory fail");
free(pb_data);
//释放返回集
if(rs)
{
OCI_ReleaseResultsets(st);
//printf("file:%s--line:%d--OCI_ReleaseResultsets(st) success\r\n",POS_INFO);
}
//清除声明
if(st)
{
OCI_StatementFree(st);
//printf("file:%s--line:%d--OCI_StatementFree(st) success\r\n",POS_INFO);
}
pthread_mutex_unlock(&mutex_cn);
return -1;
}
pb_data->num = icnt;
pb_data->row_len = strlen(buf_data)+1;
//数据全部Copy过来,不是地址赋值过来
memcpy(pb_data->row_data,buf_data,strlen(buf_data)+1);//sizeof(rs)==4,forever
pb_data->row_data[strlen(buf_data)] = '\0';
//将每一行数据作为一个结点存放在链表中
//printf("file:%s--line:%d--pb_data->row_data=%s\r\n",POS_INFO,pb_data->row_data);
zlog_debug(fzs_lib_mod_log,"--pb_data->row_data=%s",pb_data->row_data);
rs_head = rs_link_insert(rs_head,pb_data);
}
//总行数
*row_num = icnt;
*rs_data = rs_head;
//将rs_head指向空指针
rs_head = NULL;
//rs_link_print(*rs_data);
//将每行数据内的0x1替换为0x0
for(rs_node=*rs_data;rs_node;rs_node=rs_node->next)
{
for(ptemp = rs_node->row_data,p1temp = ptemp+rs_node->row_len;ptemp < p1temp;ptemp++)
{
if(1 == *ptemp)
{
// printf("file:%s--line:%d--p=%c\r\n",POS_INFO,*p);
// zlog_debug(fzs_lib_mod_log,"--p=%c",*p);
*ptemp = 0;
// printf("file:%s--line:%d--p=%c\r\n",POS_INFO,*p);
// zlog_debug(fzs_lib_mod_log,"--p=%c",*p);
}
}
//printf("file:%s--line:%d--rs_node->row_data=%s\r\n",POS_INFO,rs_node->row_data);
zlog_debug(fzs_lib_mod_log,"--rs_node->row_data=%s",rs_node->row_data);
}
//rs_link_print(*rs_data);
//释放format_sql内存空间
free(format_sql);
//释放返回集
if(rs)
{
OCI_ReleaseResultsets(st);
//printf("file:%s--line:%d--OCI_ReleaseResultsets(st) success\r\n",POS_INFO);
}
//清除声明
if(st)
{
OCI_StatementFree(st);
//printf("file:%s--line:%d--OCI_StatementFree(st) success\r\n",POS_INFO);
}
#ifdef SWITCH_LOG
if(1 == db_en_chs_flag)
{
zlog_info(fzs_lib_mod_log,"当前数据库查询花费时间%lu us",(end1_temp-st1_temp));
}
else
{
zlog_info(fzs_lib_mod_log,"The current database query cost time:%lu us",(end1_temp-st1_temp));
}
#endif
pthread_mutex_unlock(&mutex_cn);
return 0;
}
本代码实现中,没有实现主函数,实现了具体处理SQL语句及对获取的数据处理(没有解析出针对每一列),是作为通用函数处理的。[/mw_shl_code]
总结:
1,在对oracle数据库开发中,使用oracle公司开发的OCILIB库开发,相比oci更简单,具体OCILIB库的好处和实现demo请查阅OCILIB库说明;
2,在不使用OCILIB库函数解析从数据库获取的数据时,可以把SQL语句当着字符串处理,通过连接符使多列转为一列SQL语句,这样查询获取的数据也是一列;
3,对OCILIB库函数也要使用得当,掌握基本使用函数和使用技巧。