有人可以帮我如何从sql到listview检索特定的列表数据吗?我尝试检索所有数据,它成功地工作,但是当我尝试使用Where子句检索特定的数据时,它崩溃了。有什么帮助吗?还是有其他方法可以检索特定的数据列表
这是我尝试检索sql数据的代码的一部分
ArrayList<String> results=new ArrayList<>();
db=new DBHandler(this);
ListView listView = (ListView) findViewById(R.id.list);
lst.setText(callquiz);
String YOUR_QUERY = "SELECT * FROM user WHERE title= "+ callquiz;
//callquiz is a string variable i use to hold the data specifier for my table
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.rawQuery(YOUR_QUERY,null);
if (c != null ) {
if (c.moveToFirst()) {
do { results.add(c.getString(c.getColumnIndex(COL_ANS)));
}while (c.moveToNext());
}
}
ArrayAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results);
listView.setAdapter(adapter);
这是DBHandler类
public class DBHandler extends SQLiteOpenHelper {
public static final String DB_NAME = "AnswerTables.db";
public static final int DB_VERSION = 2;
public static final String TABLE = "user";
public static final String COL_TASK_TITLE = "title";
public static final String ID = "id";
public static final String COL_ANS="answer";
public DBHandler(Context context) {
super(context, DB_NAME, null, DB_VERSION);
SQLiteDatabase db=getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
String createtable="CREATE TABLE " + TABLE + " ( "+ ID +" INTEGER PRIMARY KEY AUTOINCREMENT, "+ COL_TASK_TITLE+ " TEXT NOT NULL,"+ COL_ANS+" TEXT NOT NULL);";
db.execSQL(createtable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE);
onCreate(db);
}
public boolean insertData(String name,String quiz){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues contex=new ContentValues();
contex.put(COL_TASK_TITLE,name);
contex.put(COL_ANS,quiz);
long result=db.insert(TABLE,null,contex);
if(result==-1)
{
return false;
}else{
return true;
}
}
}
答案 0 :(得分:0)
出于安全原因(我不确定),每当您执行Where或另一种与值匹配的语句时,匹配的值都应该像“?”一样,因此您的语句看起来像这样
String QUERY = "SELECT * FROM user WHERE title=?";
其余代码如下:
//callquiz is a string variable i use to hold the data specifier for my table
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.rawQuery(QUERY, new String[]{callquiz});
如果查询未返回任何数据,请尝试将撇号放在“?”之间在声明中。
答案 1 :(得分:0)
您的问题很可能是由于找不到列名。
这是因为您没有将callquiz字符串括在引号中,并且如果该值不是数字,则它将值视为列名。
可以使用:-
解决此问题String YOUR_QUERY = "SELECT * FROM user WHERE title= '"+ callquiz + "'";
但是,防止此类错误的更好方法是改用SQLiteDatabase类的 query 便捷方法。这也可以防止SQL注入。
要利用这一点,您可以编写代码而不是:-
字符串YOUR_QUERY =“ SELECT * FROM user WHERE title =”“ + callquiz; // callquiz是一个字符串变量,我用来保存表的数据说明符 SQLiteDatabase dbfectch; dbfectch = db.getWritableDatabase(); 光标c = dbfectch.rawQuery(YOUR_QUERY,null);
是:-
//String YOUR_QUERY = "SELECT * FROM user WHERE title= "+ callquiz; //<<<<<<<<<< NOT NEEDED
//callquiz is a string variable i use to hold the data specifier for my table
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.query(DBHandler.TABLE, //<<<<<<<<<< The table to query
null, //<<<<<<<<<< The columns null for all eqv to *
DBHandler.COL_TASK_TITLE + "=?", //<<<<<<<<<< The WHERE clause ? is replaced on a 1 for 1 basis from the WHERE args (next paramter)
new String[]{callquiz}, //<<<<<<<<<< The WHERE args that replace ?
null, //<<<<<<<<<< GROUP BY clause, null = no clause
null, //<<<<<<<<<< HAVING clause, null = no clause
null //<<<<<<<<<< ORDER BY clause, null = no clause
);
关于正确性检查,从SQLiteDabase方法返回的游标的 null 是无用的,并且可能导致问题。这样的游标将永远不会为空,而是如果现在提取行,则游标将有0行。 moveTo ??????如果无法进行移动,则方法将返回false(另外,Cursor getCount 方法将返回0)。
while (cursor.moveToNext) {....}
使用while (cursor.MoveToNext) { do your stuff.... }
遍历游标更为简单。因此,更正确的代码可能是:-
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.query(DBHandler.TABLE, //<<<<<<<<<< The table to query
null, //<<<<<<<<<< The columns null for all eqv to *
DBHandler.COL_TASK_TITLE + "=?", //<<<<<<<<<< The WHERE clause ? is replaced on a 1 for 1 basis from the WHERE args (next parameter)
new String[]{callquiz}, //<<<<<<<<<< The WHERE args that replace ?
null, //<<<<<<<<<< GROUP BY clause, null = no clause
null, //<<<<<<<<<< HAVING clause, null = no clause
null //<<<<<<<<<< ORDER BY clause, null = no clause
);
while (c.moveToNext()) {
results.add(c.getString(c.getColumnIndex(DBHandelr.COL_ANS)));
}
有时,列表可能会更改(例如,您可能有删除行的代码),您实际上并不想每次实例化一个新适配器,而是通过调用适配器的NotifyDatasetChanged方法来刷新列表。因此,仅跟随:-
ArrayAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results);
listView.setAdapter(adapter);
相反,您可以使用:-
if (adapter == null) {
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results);
listview.setAdapter(adapter);
} else {
adapter.notifyDatasetChanged();
}
通常,您会希望用户与列表进行交互(例如,长按要删除的项目(不建议单击中间没有确认删除的中间对话框的情况下,不建议单击,长单击至少可以防止意外单击) ))。
使用 ArrayList 的问题在于,只有显示的字符串是直接可用的,并且可能不足以标识基础行。宁愿使用ArrayList更好,因为您通常会拥有一个这样的对象(在您的情况下, your_more_comprehensive_object 可能是一个 user 对象,其中包含相应 ID 列)。但是,如果不使用CustomAdapter或在对象的类中覆盖toString方法,则会受到限制。
对于ListView,更简单的解决方案是改为使用游标适配器。使用CursorAdapter(例如SimpleCursorAdapter)确实需要存在专门命名为 _id 的列。
因此,您可能希望考虑以下基于您的代码的工作示例(希望上面的说明中的注释将解释所有内容):-
DBHanlder.java
public class DBHandler extends SQLiteOpenHelper {
public static final String DB_NAME = "AnswerTables.db";
public static final int DB_VERSION = 2;
public static final String TABLE = "user";
public static final String COL_TASK_TITLE = "title";
//public static final String ID = "id"; //<<<<<<<<<< replaced by line below
public static final String ID = BaseColumns._ID; //<<<<<<<<<< make column the standard _id
public static final String COL_ANS="answer";
public DBHandler(Context context) {
super(context, DB_NAME, null, DB_VERSION);
SQLiteDatabase db=getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
String createtable="CREATE TABLE " + TABLE + " ( "+ ID +" INTEGER PRIMARY KEY, "+ COL_TASK_TITLE+ " TEXT NOT NULL,"+ COL_ANS+" TEXT NOT NULL);";
db.execSQL(createtable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE);
onCreate(db);
}
public boolean insertData(String name,String quiz){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues contex=new ContentValues();
contex.put(COL_TASK_TITLE,name);
contex.put(COL_ANS,quiz);
long result=db.insert(TABLE,null,contex);
if(result==-1)
{
return false;
}else{
return true;
}
}
//<<<<<<<<<< new method
public Cursor getAllUsersWithTitle(String title) {
String whereclause = COL_TASK_TITLE + "=?";
String[] whereargs = new String[]{title};
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE,null,whereclause,whereargs,null,null,null);
}
//<<<<<<<<<< new method
public boolean deleteUserById(long id) {
String whereclause = ID + "=?";
String[] whereargs = new String[]{String.valueOf(id)};
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE,whereclause,whereargs) > 0);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
Context context; //<<<<<<<<<< ADDED for Toast from handler
ListView listView;
DBHandler db;
Cursor cursor;
SimpleCursorAdapter sca;
String callquiz;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
listView = this.findViewById(R.id.list);
db = new DBHandler(this);
addSomeUsers(); //<<<<<<<<<< Add some testing data
callquiz = "Fred";
refreshOrInitialiseListView(); //<<<<<<<<<< handle the listview
//<<<<<<<<<< EXTRA >>>>>>>>>>
//<<<<<<<<<< Add A click Listener to toast the clicked item
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(context,
"You clicked on the Item with a title of " +
cursor.getString(cursor.getColumnIndex(DBHandler.COL_TASK_TITLE)) +
" and ans is " + cursor.getString(cursor.getColumnIndex(DBHandler.COL_ANS)) +
" whose ID is " + String.valueOf(l) //<<<<<<<<<< note 4th parameter passed is the id
,
Toast.LENGTH_SHORT).show();
}
});
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
db.deleteUserById(l);
refreshOrInitialiseListView();
return true; //<<<<<<<<<<<< indicate that the long click has been handled
}
});
}
//<<<<<<<<<< ADDED to clean up (not needed for the main activity but does not hurt)
@Override
protected void onDestroy() {
cursor.close();
db.close();
super.onDestroy();
}
//<<<<<<<<<< ADDED to refresh the ListView is the activity is resumed e.g. return from invoked activity.
@Override
protected void onResume() {
super.onResume();
refreshOrInitialiseListView();
}
private void refreshOrInitialiseListView() {
cursor = db.getAllUsersWithTitle(callquiz);
if (sca == null) {
sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
cursor,
new String[]{DBHandler.COL_TASK_TITLE,DBHandler.COL_ANS},
new int[]{android.R.id.text1,android.R.id.text2},
0
);
listView.setAdapter(sca);
} else {
sca.swapCursor(cursor);
}
}
private void addSomeUsers() {
if (DatabaseUtils.queryNumEntries(db.getWritableDatabase(),DBHandler.TABLE) < 1) {
db.insertData("Fred","Freds Quiz");
db.insertData("Fred","Fred's 2nd Quiz");
db.insertData("Fred","Fred's 3rd quiz");
db.insertData("Mary","Mary's first quiz");
db.insertData("Mary","mary's 2nd quiz");
db.insertData("Mary","Mary's 3rd quiz");
}
}
}
从头开始运行该应用程序将导致ListView中列出6行(项目)中的3行(显示标题和答案)。
注意:该工作示例旨在用作演示并具有局限性(例如,如果您删除所有项目/行,那么除非您删除数据库,否则不会显示任何内容)