I am trying to retrieve an integer from my SQLite database and my current query crashes my program. This is what I have so far:
*/
public int getWin(String id){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT " + COL3 + " FROM " + TABLE_NAME +
" WHERE " + COL2 + " = '" + id + "'";
Log.d(TAG, "updateName: query: " + query);
db.execSQL(query);
int win = Integer.parseInt(query);
return win;
}
I am not sure why this will not work. Thanks in advance.
You are trying to convert the value SELECT ......... into a number as per int win = Integer.parseInt(query);.
For a SELECT statment you need you need to retrieve a Cursor (result set), via either the query or rawQuery SQLiteDatabase method and then extract the value(s) from the method and to then access the respective column from the respective row(s).
I believe that you would use something like :-
public int getWin(String id){
SQLiteDatabase db = this.getWritableDatabase();
int rv = -1; //<<<<<<<<<< ADDED default value to return if no row found
String query = "SELECT " + COL3 + " FROM " + TABLE_NAME +
" WHERE " + COL2 + " = '" + id + "'";
Log.d(TAG, "updateName: query: " + query);
Cursor csr = db.rawQuery(query,null); //<<<<<<<<<< CHANGED to get the Cursor returned
// ADDED the following IF construct
if (csr.moveToFirst()) {
rv = csr.getInt(csr.getColumnIndex(COL3));
}
//int win = Integer.parseInt(query); //<<<<<<<<<< DELETED (commented out)
csr.close(); //<<<<<<<<<< ADDED should always close a Cursor when done with it
return rv; //<<<<<<<<<< return the value (-1 if no row found)
}
This assumes that you just want the value from a single row as identified by the WHERE clause.
If possible it is recommended to a) not build the query with direct values (makes it vulnerable to SQL Injection) and to b) utilise the convenience query method.
Apply both a and b and your code could be :-
public int getWin(String id){
SQLiteDatabase db = this.getWritableDatabase();
int rv = -1;
String whereclause = COL2 + "=?"; //<<<<<<<<<< where clause without where and ? for value that will be passed
String[] whereargs = new String[]{String.valueOf(id)}; //<<<<<<<<<< arguments used by the whereclause ? replaced on a 1 for 1 basis
String[] columns = new String[]{COL3}; //<<<<<<<<<< the columns to extract as a String array
Cursor csr = db.query(TABLE_NAME,columns,whereclause,whereargs,null,null,null);
if (csr.moveToFirst()) {
rv = csr.getInt(csr.getColumnIndex(COL3));
}
csr.close();
return rv;
}
I am working on a student grade submission program that accepts the following inputs: Student ID, Student First Name, Student Last Name, Class ID, Class Name, Grade Points, and Letter Grade. In order to prevent data redundancy I have created three different tables. However when attempting to "modify" or "delete" an entry with two values from distinct tables I am running into a problem. (For instance delete WHERE student.id is equal to the student.id in STUDENT_TABLE and WHERE class.id is equal to the class.id in the CLASS_TABLE)
With that being said, here is my current Modify code for Modifying a Student Class. I need to modify in a way in which the student.id and class.id are associated (Which are Located in two different Tables)
modifyclass.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(studentid.getText().toString().trim().length()==0 || classid.getText().toString().trim().length()==0 || classname.getText().toString().trim().length()==0)
{
showMessage("Error", "Please enter Student & Class ID to update class. \n\nAll other Field Entries will be ignored");
return;
}
Cursor c=db.rawQuery("SELECT * FROM CLASS_TABLE WHERE classid='"+classid.getText()+"'", null);
if(c.moveToFirst())
{
db.execSQL("UPDATE CLASS_TABLE SET classid='"+classid.getText()+"',classname='"+classname.getText()+"' WHERE studentid='"+studentid.getText()+"' AND classid='"+classid.getText()+"'");
showMessage("Success", "Class Record Modified");
}
else
{
showMessage("Error", "Invalid First and Last name or Class ID");
}
clearText();
}
});
EDIT:
Here are my tables for reference:
db=openOrCreateDatabase("STUDENTGRADES", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS STUDENT_TABLE (studentid TEXT, fname TEXT, lname TEXT)");
db.execSQL("CREATE TABLE IF NOT EXISTS CLASS_TABLE(classid TEXT PRIMARY KEY, classname TEXT UNIQUE)");
db.execSQL("CREATE TABLE IF NOT EXISTS GRADE_TABLE (studentid TEXT, classid TEXT, pointgrade INTEGER, lettergrade TEXT)");
You should never need to update multiple tables at once at least for a single change e.g. student's name has changed (student table would be changed) or say a grade changed (change the student's respective grade entry).
So I believe what would best suit are methods to update a Student's details (first or last name or both) and a method to alter the grades (again either or both).
As for deletion you could do this sequentially delete from the grades table and the from the student table or vice-versa.
As such I believe the following code includes methods deleteStudentInfo, changeStudentName, changeStudentFirstName, changeStudentLastName and changeStudentGrade and also includes example usage along with creating and populating the tables (you may wish to consider the revised schema):-
public class MainActivity extends AppCompatActivity {
public static final String DBNAME = "study";
public static final String STUDENT_TABLE_NAME = "STUDENT_TABLE";
public static final String COL_STUDENT_ID = "studentid";
public static final String COL_STUDENT_FIRSTNAME = "fname";
public static final String COL_STUDENT_LASTNAME = "lname";
public static final String CLASS_TABLE_NAME = "CLASS_TABLE";
public static final String COL_CLASS_ID = "classid";
public static final String COL_CLASS_NAME = "classname";
public static final String GRADE_TABLE_NAME = "GRADE_TABLE";
public static final String COL_GRADE_POINTGRADE = "pointgrade";
public static final String COL_GRADE_LETTERGRADE = "lettergrade";
public static final String BY_STUDENTID = COL_STUDENT_ID + "=?";
public static final String BY_CLASSID = COL_CLASS_ID + "=?";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SQLiteDatabase db = openOrCreateDatabase(DBNAME,Context.MODE_PRIVATE,null);
db.execSQL("CREATE TABLE IF NOT EXISTS " + STUDENT_TABLE_NAME + " (" +
COL_STUDENT_ID + " TEXT PRIMARY KEY, " +
COL_STUDENT_FIRSTNAME + " TEXT," +
COL_STUDENT_LASTNAME + " TEXT)"
);
db.execSQL("CREATE TABLE IF NOT EXISTS " + CLASS_TABLE_NAME + "(" +
COL_CLASS_ID + " TEXT PRIMARY KEY," +
COL_CLASS_NAME + " TEXT UNIQUE " +
")"
);
db.execSQL("CREATE TABLE IF NOT EXISTS " + GRADE_TABLE_NAME + "(" +
COL_STUDENT_ID + " TEXT, " +
COL_CLASS_ID + " TEXT, " +
COL_GRADE_POINTGRADE + " INTEGER, " +
COL_GRADE_LETTERGRADE + " TEXT" +
")"
);
db.execSQL("INSERT OR IGNORE INTO " + STUDENT_TABLE_NAME +
" VALUES" +
"('00001','Fred','Smith')," +
"('00010','Mary','Thomas')," +
"('00910','Angela','Jones')"
);
db.execSQL("INSERT OR IGNORE INTO " + CLASS_TABLE_NAME +
" VALUES" +
"('001','English')," +
"('101','Mathematics')," +
"('201','Chemistry')"
);
db.execSQL("INSERT OR IGNORE INTO " + GRADE_TABLE_NAME +
" VALUES" +
" ('00001','001',99,'A'), -- Fred Smith has 99 point grade as an A in English\n" +
" ('00001','101',25,'F'), -- Fred Smith has 25 point grade as an F on Mathematics\n" +
" ('00010','201',76,'B'), -- Angela Jones 76 a B in Chemistry\n" +
" ('00910','101',50,'C'), \n" +
" ('00910','201',63,'C'),\n" +
" ('00910','001',89,'A')\n" +
";"
);
changeStudentName(db,"00001","Joe","Bloggs");
changeStudentFirstName(db,"00001","Harry");
changeStudentLastName(db,"00001","Hoffmann");
// e.g. won't change due to -1 (skip pointsgrade) and null (skip lettergrade)
changeStudentGrade(db,"00001","001",-1,null);
// Change both
changeStudentGrade(db,"00001","001",25,"D");
changeStudentGrade(db,"00001","001",27,null);
// Ooops invalid student id
if (deleteStudentInfo(db,"001")) {
Log.d("DELETION","Student 001 deleted.");
} else {
Log.d("DELETION","Ooops Student 001 not deleted?????");
}
// Corrected Student ID
if (deleteStudentInfo(db,"00001")) {
Log.d("DELETION","Student 001 deleted.");
} else {
Log.d("DELETION","Ooops Student 001 not deleted?????");
}
}
private boolean deleteStudentInfo(SQLiteDatabase db, String studentid) {
String tag = "STUDENT_DELETE";
String student_table = "STUDENT_TABLE";
String grade_table = "GRADE_TABLE";
long pre_delete_student_count = DatabaseUtils.queryNumEntries(db,student_table);
long pre_delete_grade_count = DatabaseUtils.queryNumEntries(db,grade_table);
String whereclause = "studentid =?";
String[] whereargs = {studentid};
db.delete(student_table,whereclause,whereargs);
db.delete(grade_table,whereclause,whereargs);
long post_delete_student_count = DatabaseUtils.queryNumEntries(db,student_table);
long post_delete_grade_count = DatabaseUtils.queryNumEntries(db,grade_table);
Log.d(
tag,
"Number of Students deleted from " +
student_table + " is " +
String.valueOf(
pre_delete_student_count - post_delete_student_count
));
Log.d(
tag,
"Number of Grades deleted from " + grade_table + " is " +
String.valueOf(
pre_delete_grade_count - post_delete_grade_count
)
);
if ((pre_delete_student_count + pre_delete_grade_count) != (post_delete_student_count + post_delete_grade_count)) {
return true;
}
return false;
}
/**
* Flexible Student Name Change
*
* #param db The SQliteDatabase
* #param studentid The studentid (String)
* #param newfirstname The new firstname, null or blank to leave as is
* #param newlastname the new lastname, null or blank to leave as is
*/
private void changeStudentName(SQLiteDatabase db, String studentid, String newfirstname, String newlastname ) {
//Anything to do? if not do nothing
if ((newfirstname == null || newfirstname.length() < 1) && (newlastname == null || newlastname.length() < 1)) {
return;
}
ContentValues cv = new ContentValues();
if (newfirstname != null && newfirstname.length() > 0) {
cv.put(COL_STUDENT_FIRSTNAME,newfirstname);
}
if (newlastname != null && newlastname.length() > 0) {
cv.put(COL_STUDENT_LASTNAME,newlastname);
}
// Overcautious check
if (cv.size() < 1) {
return;
}
db.update(STUDENT_TABLE_NAME,cv,BY_STUDENTID,new String[]{studentid});
}
/**
* Change a Student's First Name (invokes changeStudentName method)
* #param db The SQLiteDatabase
* #param studentid The student's id (String)
* #param newfirstname The new first name to apply
*/
private void changeStudentFirstName(SQLiteDatabase db, String studentid, String newfirstname) {
changeStudentName(db,studentid,newfirstname,null);
}
/**
* Change a Student's Last Name (invokes changeStudentName method)
* #param db
* #param studentid
* #param newlastname
*/
private void changeStudentLastName(SQLiteDatabase db, String studentid, String newlastname) {
changeStudentName(db,studentid,null,newlastname);
}
/**
* Change a students grade (allowing just one (points/letter))
* #param db
* #param studentid
* #param classid
* #param newpointsgrade
* #param newlettergrade
*/
private void changeStudentGrade(SQLiteDatabase db, String studentid, String classid, int newpointsgrade, String newlettergrade) {
// Anything to do? if not do nothing
if (newpointsgrade < 0 && (newlettergrade == null || newlettergrade.length() < 1)) {
return;
}
ContentValues cv = new ContentValues();
if (newpointsgrade >= 0) {
cv.put(COL_GRADE_POINTGRADE,newpointsgrade);
}
if (newlettergrade != null && newlettergrade.length() > 0) {
cv.put(COL_GRADE_LETTERGRADE,newlettergrade);
}
String whereclause = COL_STUDENT_ID + "=? AND " + COL_CLASS_ID + "=?";
String[] whereargs = new String[]{studentid,classid};
db.update(GRADE_TABLE_NAME,cv,whereclause,whereargs);
}
}
I have pickDateTime function, that restricts the user of choosing times that are in past. Current time - is the "minimum" time allowed.
This is the function:
public void pickDateTime(View view) {
Calendar c = Calendar.getInstance();
currentYear = c.get(Calendar.YEAR);
currentMonth = c.get(Calendar.MONTH);
currentDay = c.get(Calendar.DAY_OF_MONTH);
currentHour = c.get(Calendar.HOUR_OF_DAY);
currentMinute = c.get(Calendar.MINUTE);
DatePickerDialog datePickerDialog = new DatePickerDialog(NewMissionUser.this
, new DatePickerDialog.OnDateSetListener() {
#Override
public void onDateSet(DatePicker datePicker, int year, int month, int day) {
Log.d(TAG,"Chose: year: " + year + " , month: " + (month+1) + " day: " + day);
missionYear = year;
missionMonth = (month+1);
missionDay = day;
TimePickerDialog timePickerDialog = new TimePickerDialog(NewMissionUser.this, new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker timePicker, int hourOfDay, int minute) {
missionTime = missionDay+"/"+missionMonth+"/"+missionYear + " " +hourOfDay + ":" + minute;
Log.d(TAG,"missionTime: " + missionTime);
if (isPast(missionTime)){
Log.d(TAG,"mission time in past!");
Toast.makeText(getApplicationContext(), "APP Mission inserted in past, ignoring date, default date is now.",Toast.LENGTH_LONG);
Toast.makeText(NewMissionUser.this, "Mission inserted in past, ignoring date, default date is now.",Toast.LENGTH_LONG);
Toast.makeText(getBaseContext(), "BASE Mission inserted in past, ignoring date, default date is now.",Toast.LENGTH_LONG);
missionTime = currentDay+"/"+currentMonth+"/"+currentYear + " " +currentHour + ":" + currentMinute;
}
}
},currentHour, currentMinute, true);
timePickerDialog.show();
}
},currentYear, currentMonth, currentDay);
datePickerDialog.show();
}
This is the class:
public class NewMissionUser extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener, GmapFragmentNewMission.TextClicked
The problem is, that the Toast won't show up in either of these tries.
The Log DOES appear, and in debug I see that the code reaches this point and isPast function is behaving as expected.
Why the Toast won't come up? Thanks.
You're missing the call to show() the Toast:
Toast.makeText(getApplicationContext(), "...",Toast.LENGTH_LONG).show();
I have problems deleting the rows from a table.
I have 2 tables with the following definition:
private static final String DATABASE_TABLEELEMENTS = "elements";
public static final String KEY_ROWELEMENTID = "_id";
public static final String KEY_STUDYID = "idstudy";
public static final String KEY_ELEMENTCODE = "code_element";
public static final String KEY_ELEMENTNAME = "description_element";
private static final String DATABASE_TABLETIME = "times";
public static final String KEY_ROWTIME = "_id";
public static final String KEY_ELEMENTID = "idelement";
public static final String KEY_HOURDATE = "hour_date";
public static final String KEY_OBSERVEDYTIME = "observedtime";
public static final String KEY_OBSERVEDACTIVITY = "observedactivity";
both tables are related:
elements._id = times.idelement
I want to delete all rows in table "times" which has the "idstudy" from table "elements" that the user has selected:
For this I created the following function:
public void ResetDataStudies(String selectedid) {
String querytimes = "DELETE FROM "
+ "times"
+ " WHERE "
+ "times.idelement"
+ " IN "
+ "(SELECT "
+ "elements._id"
+ " FROM "
+ "elements"
+ " WHERE "
+ "elements.idstudy = ?)";
ourDatabase.rawQuery(querytimes, new String[] { selectedid });
}
I don't receive a specific error, but after executing it the data has not been deleted.
See below the data type:
db.execSQL(" CREATE TABLE " + DATABASE_TABLEELEMENTS + " (" +
KEY_ROWELEMENTID + " INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT, " +
KEY_ELEMENTCODE + " INTEGER NOT NULL, " +
KEY_ELEMENTNAME + " TEXT, " +
KEY_STUDYID + " TEXT NOT NULL REFERENCES " + DATABASE_TABLEACOUNT + "("+ KEY_ROWSTUDYID +") ON DELETE CASCADE ");
db.execSQL(" CREATE TABLE " + DATABASE_TABLETIME + " (" +
KEY_ROWTIME + " INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT, " +
KEY_HOURDATE + " INTEGER NOT NULL, " +
KEY_OBSERVEDYTIME + " TEXT NOT NULL, " +
KEY_OBSERVEDACTIVITY + " TEXT NOT NULL, " +
KEY_ELEMENTID + " TEXT NOT NULL REFERENCES " + DATABASE_TABLEELEMENTS + "("+ KEY_ROWELEMENTID +") ON DELETE CASCADE ");
}
I have updated my statements but now I receive an error while creating the tables:
error near cascade statement
When you create the table, the foreign key needs to be ON DELETE CASCADE. e.g.
FOREIGN KEY ("+KEY_ELEMENTID+") REFERENCES "+DATABASE_TABLEELEMENTS+" ("+KEY_ROWELEMENTID+") ON DELETE CASCADE); "
You'll also have to tell SQLite to enforce foreign keys (otherwise they are ignored).
PRAGMA foreign_keys = ON;
See https://www.sqlite.org/foreignkeys.html.
I am working on several rawQueries to use to parse data from a table in Android. The below code works fine and returns the lowest rowid in the table.
public void firstRecord(View v){
Cursor c = db.rawQuery("SELECT * FROM surveyDB WHERE rowid = (SELECT MIN(rowid) FROM surveyDB)",null);
c.moveToFirst();
szList.add(c.getString(0));
Toast.makeText(getApplicationContext(), "Sucessful Event. szRowid is: " +szList +".", Toast.LENGTH_LONG).show();
}
I have two questions, and they are both extremely basic: 1) what is the best way to expand the above code to create language to capture the contents of other columns in this table at that specific rowid, (rowid, sampler, species, place), and display this in my application? Something like this perhaps:
((EditText)findViewById(R.id.edSpecies)).setText("");
with the proper reference replacing "" in .setText()?
String TABLE_SURVEY = "surveyDB";
String COL_ROW_ID = "rowid";
String COL_SAMPLER = "sampler";
String COL_SPECIES = "species";
String COL_PLACE = "place";
public ArrayList<SurveyRecord> getSurveyRecords()
{
ArrayList<SurveyRecord> records = new ArrayList<SurveyRecord>();
String query = "SELECT * FROM " + TABLE_SURVEY;
query += " WHERE " + COL_ROW_ID = " SELECT MIN ("
query += COL_ROW_ID + ") FROM " + TABLE_SURVEY;
Cursor c = db.rawQuery(query,null);
if(Cursor.moveToFirst())
{
do{
String sampler = c.getString(cursor.getColumnIndex(COL_SAMPLER));
String species= c.getString(cursor.getColumnIndex(COL_SPECIES));
String place = c.getString(cursor.getColumnIndex(COL_PLACE));
String rowId = c.getString(cursor.getColumnIndex(COL_ROW_ID));
records.add(new (rowId,species,place,sampler));
}while(c.moveToNext())
}
c.close();
}
public class SurveyRecord{
String mRowId;
String mSpecies;
String mPlace;
String mSampler;
public SurveyRecord(String rowId,String species,String place,String sampler)
{
this.mRowId = rowId;
this.mSpecies = species;
this.mPlace = place;
this.mSampler = sampler;
}
}
//Goes to the first record in the dataset
public void firstRecord(View v){
Cursor c = db.rawQuery("SELECT * FROM surveyDB WHERE rowid = (SELECT MIN(rowid) FROM surveyDB)",null);
c.moveToFirst();
((EditText)findViewById(R.id.edRowid))
.setText(c.getString(0));
((EditText)findViewById(R.id.edSpecies))
.setText(c.getString(1));
((EditText)findViewById(R.id.edArea))
.setText(c.getString(2));
((EditText)findViewById(R.id.edSampler))
.setText(c.getString(3));
}