将一列中的所有行连接到另一列与sqlite中的某个内容匹配/相等的位置



我正在尝试正确输出名称列中的所有行,其中IP列与C++中的客户端IP相同。这是正常工作的,但是输出是换行符上的每个名称。我想以某种方式使用concatstring或其他方法将所有名称放到同一行。当我使用我在代码中注释的方法时,它不能正常工作,因为它在while循环中——它的输出是这样的:

name
name, name2
name, name2, name3

这是不希望的。如果我把东西从while循环中移出,它要么不在范围内,要么会因为无法访问数据而因分段错误而崩溃。如果我使用bool进行检查,并且在while循环中只输出一次,则只显示列表中的第一个名称。我只想让所有的名字都显示在同一行上,比如:

name, name2, name3

下面的代码中有一个狙击手:

while ((rc = sqlite3_step(stmt3)) == SQLITE_ROW) {
std::string names(reinterpret_cast<const char*>(sqlite3_column_text(stmt3, 0)));
out(ECHO_SERV, names.c_str());
/*char msg[MAXTRANS];
string buf;
formatstring(msg)("%s, ", names.c_str());
concatstring(buf, msg, MAXTRANS);
out(ECHO_SERV, buf);*/
}

非常感谢您的帮助。感谢您抽出时间!

这是完整的代码:

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %sn", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("n");
return 0;
}

void savestats(clientinfo *ci)
{
sqlite3 *db;
char *zErrMsg = 0;
int  rc;
const char *sql;
bool name_match, ip_match;
const char* player_database_names;
const char* player_database_ips;
char *p_name = ci->name;
char *p_ip = ci->ip;

//Open database
rc = sqlite3_open("playerinfo.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %sn", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stdout, "Opened database successfullyn");
}
//Handle errors
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL Database Error: %sn", zErrMsg);
sqlite3_free(zErrMsg);
//Fetch names from database for comparison
}else{
//name match
sqlite3_stmt *stmt;
defformatstring(sqlstrprep)("SELECT NAME FROM PLAYERINFO");
rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);

while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
//int id = sqlite3_column_int(stmt, 0);
player_database_names = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
if(!strcmp(player_database_names, p_name)) name_match = true;
else name_match = false;
}
//ip match (doesn't work)
sqlite3_stmt *stmt2;
defformatstring(sqlstrprep2)("SELECT IP FROM PLAYERINFO");
rc = sqlite3_prepare_v2(db, sqlstrprep2, -1, &stmt2, NULL);

while ((rc = sqlite3_step(stmt2)) == SQLITE_ROW) {
int id = sqlite3_column_int(stmt2, 6);
player_database_ips = reinterpret_cast<const char*>(sqlite3_column_text(stmt2, id));
//if(!strcmp(player_database_ips, p_ip)) ip_match = true; //seg fault EXC_BAD_ACCESS
if(player_database_ips == p_ip) ip_match = true;
else ip_match = false;
}
}

//Create the table if it doesn't exist
sql = "CREATE TABLE IF NOT EXISTS PLAYERINFO("    
"NAME                       TEXT    NOT NULL,"    
"FRAGS                       INT    NOT NULL,"    
"DEATHS                      INT    NOT NULL,"    
"FLAGS                       INT    NOT NULL,"    
"PASSES                      INT    NOT NULL,"    
"IP                         TEXT    NOT NULL,"    
"ACCURACY          DECIMAL(4, 2)    NOT NULL,"    
"KPD               DECIMAL(4, 2)    NOT NULL);";
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQLITE3 ERROR @ CREATE TABLE IF NOT EXISTS: %sn", zErrMsg);
sqlite3_free(zErrMsg);
}else{
if(!name_match) fprintf(stdout, "No previous record found under that namen");
else fprintf(stdout, "Found name and IP already, updating record insteadn");
}

char sqlINSERT[256];
char sqlUPDATE[1000];
int p_frags = ci->state.frags;
int p_deaths = ci->state.deaths;
int p_flags = ci->state.flags;
int p_passes = ci->state.passes;
int p_acc = (ci->state.damage*100)/max(ci->state.shotdamage, 1);
int p_kpd = (ci->state.frags)/max(ci->state.deaths, 1);

//name and ip are different
if(!name_match) {
sprintf(sqlINSERT, "INSERT INTO PLAYERINFO( NAME,FRAGS,DEATHS,FLAGS,PASSES,IP,ACCURACY,KPD ) VALUES ('%s', %d, %d, %d, %d, '%s', %d, %d)",p_name,p_frags,p_deaths,p_flags,p_passes,p_ip,p_acc,p_kpd);
rc = sqlite3_exec(db, sqlINSERT, callback, 0, &zErrMsg);
}
//name is the same, update the database if the new information is > than db_info
else if(name_match)  {
sprintf(sqlUPDATE,
"UPDATE PLAYERINFO SET FRAGS = %d+(SELECT FRAGS FROM PLAYERINFO) WHERE NAME = '%s';"     
"UPDATE PLAYERINFO SET DEATHS = %d+(SELECT DEATHS FROM PLAYERINFO) WHERE NAME = '%s';"   
"UPDATE PLAYERINFO SET FLAGS = %d+(SELECT FLAGS FROM PLAYERINFO) WHERE NAME = '%s';"     
"UPDATE PLAYERINFO SET PASSES = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';"   
"UPDATE PLAYERINFO SET ACCURACY = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';" 
"UPDATE PLAYERINFO SET KPD = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';",
ci->state.frags, ci->name, ci->state.deaths, ci->name, ci->state.flags, ci->name, ci->state.passes, ci->name, p_acc, ci->name, p_kpd, ci->name);
rc = sqlite3_exec(db, sqlUPDATE, callback, 0, &zErrMsg);
}
if( rc != SQLITE_OK ){
fprintf(stderr, "SQLITE3 ERROR @ INSERT & UPDATE: %sn", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Playerinfo modifiedn");
}
sqlite3_close(db);
}

void getstats(clientinfo *ci)
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";

/* Open database */
rc = sqlite3_open("playerinfo.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %sn", sqlite3_errmsg(db));
exit(0);
}

//rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL Database Error: %sn", zErrMsg);
sqlite3_free(zErrMsg);
}else{
sqlite3_stmt *stmt;
//defformatstring(sqlstrprep)("SELECT * FROM PLAYERINFO WHERE NAME GLOB '%s*';", ci->name);
defformatstring(sqlstrprep)("SELECT NAME,FRAGS,DEATHS,FLAGS FROM PLAYERINFO WHERE NAME == '%s';", ci->name);
rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);

bool necho = false;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
//int id = sqlite3_column_int(stmt, 0);
const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
const char* frags = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
const char* deaths = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
const char* flags = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));
if(!necho) {
out(ECHO_SERV, "Name: f2%s f7Frags: f0%s f7Deaths: f3%s f7Flags: f5%s", name,frags,deaths,flags);
out(ECHO_CONSOLE, "Name: %s, Frags: %s, Deaths: %s, Flags: %s", name,frags,deaths,flags);
necho = true;
}
}
//returns names
sqlite3_stmt *stmt3;
defformatstring(sqlstrprep3)("SELECT NAME FROM PLAYERINFO WHERE IP == '%s';", ci->ip);
rc = sqlite3_prepare_v2(db, sqlstrprep3, -1, &stmt3, NULL);

while ((rc = sqlite3_step(stmt3)) == SQLITE_ROW) {
std::string names(reinterpret_cast<const char*>(sqlite3_column_text(stmt3, 0)));
out(ECHO_SERV, names.c_str());
/*char msg[MAXTRANS];
string buf;
formatstring(msg)("%s, ", names.c_str());
concatstring(buf, msg, MAXTRANS);
out(ECHO_SERV, buf);*/
}
}
sqlite3_close(db);
}

这是解决方案,它从列NAME中获取所有行,其中IP=我们的客户端IP。

void QServ::getnames(clientinfo *ci) {
if(enable_sqlite_db) {
sqlite3_stmt *stmt3;
sqlite3 *db;
int rc;
rc = sqlite3_open("playerinfo.db", &db);
defformatstring(sqlstrprep3)("SELECT group_concat(NAME, ', ') FROM PLAYERINFO WHERE IP == '%s';", ci->ip);
rc = sqlite3_prepare_v2(db, sqlstrprep3, -1, &stmt3, NULL);
while ((rc = sqlite3_step(stmt3)) == SQLITE_ROW) {
std::string names(reinterpret_cast<const char*>(sqlite3_column_text(stmt3, 0)));
defformatstring(nmsg)("Names from IP f2%sf7: %s", ci->ip, names.c_str());
out(ECHO_SERV, nmsg);
}
sqlite3_close(db);
}
}

最新更新