您的问题是当没有要读取的行时,您正在尝试读取第 0 行(第一行)。
这是因为您没有检查是否有要读取的行。您可以使用 Cursor 的 getCount() 方法或通过检查 Cursor 的 move???? 方法的结果进行检查。
即如果无法进行移动,大多数 move???? 方法将返回 false。例如你可以使用if (res.moveToFirst()) { ..... do your stuff } else { .... handle no rows if needed }。
但是,考虑到您的评论:-
我们的目的只是获取有关列的信息,因此我们不会
需要数据。出于这个原因,最好的 where 子句是 1=2,它总是
false(对于任何包含任何列的表)
然后,您可以使用table_info PRAGMA 语句来确定列类型,该语句不需要从可以从 sqlite_master 获取的 SQL 中提取列类型。
你可以有一个通用/通用的方法,例如:-
public Cursor getTableInfo(String table) {
return this.getWritableDatabase().rawQuery("PRAGMA table_info(" + table + ")",null);
}
然后调用它,例如,使用类似的东西:-
public class MainActivity extends AppCompatActivity {
public static final String col_table_info_cid = "cid";
public static final String col_table_info_name = "name";
public static final String col_table_info_type = "type";
public static final String col_table_info_notnull = "notnull";
public static final String col_table_info_default_value = "dflt_value";
public static final String col_table_info_primary_key = "pk";
DBHelper mDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);
String table_to_look_at = "gameinfo"; //<<<<< The table to look at
Cursor csr = mDBHlpr.getTableInfo(table_to_look_at);
StringBuilder sb = new StringBuilder("Columns for Table " + table_to_look_at);
while (csr.moveToNext()) {
sb.append("\n\tColumn Name=")
.append(csr.getString(csr.getColumnIndex(col_table_info_name)))
.append(" Column Type=")
.append(csr.getString(csr.getColumnIndex(col_table_info_type)))
;
}
Log.d("TABLE INFO",sb.toString());
}
以上可能导致:-
07-24 22:27:19.842 1255-1255/ga.gamesapp D/TABLE INFO: Columns for Table gameinfo
Column Name=_id Column Type=INTEGER
Column Name=name Column Type=TEXT
Column Name=category Column Type=TEXT
Column Name=games Column Type=TEXT
Column Name=weird Column Type=rumplestiltskin
但是这有什么用吗?
从上面的结果可以看出weird列有一个rumplestiltskin的列类型。除非您查看 3.1. Determination Of Column Affinity,否则这意味着很少,这将导致列关联为 NUMERIC(规则 5 被应用,因为没有其他规则适用)。
您可以有一个例程来确定列的类型亲和性,例如:-
private String determineColumnAffinity(String columntype) {
String uc = columntype.toUpperCase();
//rule 1
if (uc.indexOf("INT") > -1) {
return "INTEGER";
}
//rule 2
if ((uc.indexOf("CHAR") > -1) || (uc.indexOf("CLOB") > -1) || (uc.indexOf("TEXT") > -1)) {
return "TEXT";
}
//rule 3
if ((uc.length() < 1) || (uc.indexOf("BLOB") > -1)) {
return "BLOB";
}
if ((uc.indexOf("REAL") > -1) || (uc.indexOf("FLOA") > -1) || (uc.indexOf("DOUB") > -1)) {
return "REAL";
}
return "NUMERIC";
}
如果将上面的代码修改为:-
sb.append("\n\tColumn Name=")
.append(csr.getString(csr.getColumnIndex(col_table_info_name)))
.append(" Column Type=")
.append(csr.getString(csr.getColumnIndex(col_table_info_type)))
.append(" Column Affinity=")
.append(determineColumnAffinity(csr.getString(csr.getColumnIndex(col_table_info_type))))
;
你会得到:-
07-24 22:59:57.770 1408-1408/ga.gamesapp D/TABLE INFO: Columns for Table gameinfo
Column Name=_id Column Type=INTEGER Column Affinity=INTEGER
Column Name=name Column Type=TEXT Column Affinity=TEXT
Column Name=category Column Type=TEXT Column Affinity=TEXT
Column Name=games Column Type=TEXT Column Affinity=TEXT
Column Name=weird Column Type=rumplestiltskin Column Affinity=NUMERIC
然而,即便如此,这可能没什么用,因为再次提及Datatypes In SQLite Version 3,可以找到这些小宝石:-
SQLite 使用更通用的动态类型系统。在 SQLite 中,
值的数据类型与值本身相关联,而不是与其相关联
容器。
但是,SQLite 中的动态类型允许它执行以下操作:
在传统的严格类型的数据库中是不可能的。
SQLite 版本 3 数据库中的任何列,INTEGER PRIMARY 除外
KEY 列,可用于存储任何存储类的值。
因此,在上面使用的 gameinfo 表中,除了 _id 列,它是 rowid 列的别名(因此只能存储一个 INTEGER),任何类型的值可以存储在任何类型的列中,因此列类型的重要性的定义在很大程度上是无关紧要的。
例如,以下是一个有效但可能无用的表的示例,它显示了存储在列中的不同数据类型(数据类型是彩色编码的):-
补充评论:-
我的意思是直接从 Sqlite 查询是获取列的唯一方法
信息?
您可以从空游标中获取列名,但无法获取列类型,因为这需要访问行中的列。
例如以下将起作用:-
Cursor csr2 = mDBHlpr.getAllRows(); // get rows from empty table
csr2.moveToFirst();
sb = new StringBuilder("Columns for Table");
for(int i=0; i < (csr2.getColumnCount());i++) {
int ctype = 100; //<<<<<<<<<< NOT A VALID COLUMN TYPE
//ctype = csr2.getType(i); //<<<<<<<<<< cannot get the type unless there is a row
String type = "unknown";
switch (ctype) {
case Cursor.FIELD_TYPE_FLOAT:
type= "REAL";
break;
case Cursor.FIELD_TYPE_NULL:
type = "NULL";
break;
case Cursor.FIELD_TYPE_INTEGER:
type = "INTEGER";
break;
case Cursor.FIELD_TYPE_STRING:
type = "TEXT";
break;
case Cursor.FIELD_TYPE_BLOB:
type = "BLOB";
break;
}
sb.append("\n\tColumn Name=").append(csr2.getColumnName(i))
.append(" Column Type=")
.append(type)
.append(" Column Affinity=")
.append(determineColumnAffinity(type));
}
Log.d("TABLE INFO 2",sb.toString());
csr2.close();
但如果表(因此光标)为空,则删除注释掉的行将导致 android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0 异常。
- 0 理论上光标已移动到第一行。
- 如果没有 csr2.moveToFirst() 那么索引将为 -1
因此,除非表中有数据,否则不直接使用SQLite就无法确定列类型