This question already has answers here:
When does SQLiteOpenHelper onCreate() / onUpgrade() run?
(15 answers)
Closed 6 years ago.
I am trying to add a TIMESTAMP Column to my SQLite database. The column is to be used to capture timestamp data using "System.currentTimeMillis();". App is crashing and the error is from the cursor code shown below in the line with ** **. The error reads "Unable to start activity ComponentInfo{...ListActivity}: java.lang.IllegalStateException: Couldn't read row 0, col 6 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it."
Initially I set up the variable as a String in the model file. Then I tried a long and neither worked. What am I missing here?
UserData file:
...
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
DatabaseHelper.java file:
...
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE IF NOT EXISTS " + DBContract.DBEntry.TABLE_NAME +
"(" + DBContract.DBEntry.COLUMN_NAME_ID +
" INTEGER PRIMARY KEY AUTOINCREMENT,"
+ DBContract.DBEntry.COLUMN_NAME_TODO +
" TEXT,"
+ DBContract.DBEntry.COLUMN_NAME_NOTE1 +
" TEXT,"
+ DBContract.DBEntry.COLUMN_NAME_NOTE2 +
" TEXT,"
+ DBContract.DBEntry.COLUMN_NAME_DUEDATE +
" TEXT,"
+ DBContract.DBEntry.COLUMN_NAME_DUETIME +
" TEXT,"
+ DBContract.DBEntry.COLUMN_NAME_TIMESTAMP +
" TEXT" + ")";
...
public void insertIntoDB(String todo, String note1, String note2, String duedate, String duetime, long timestamp) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(DBContract.DBEntry.COLUMN_NAME_TODO, todo);
values.put(DBContract.DBEntry.COLUMN_NAME_NOTE1, note1);
values.put(DBContract.DBEntry.COLUMN_NAME_NOTE2, note2);
values.put(DBContract.DBEntry.COLUMN_NAME_DUEDATE, duedate);
values.put(DBContract.DBEntry.COLUMN_NAME_DUETIME, duetime);
values.put(DBContract.DBEntry.COLUMN_NAME_TIMESTAMP, timestamp);
db.insert(DBContract.DBEntry.TABLE_NAME, null, values);
db.close();
}
...
Cursor cursor = db.rawQuery(query,null);
try {
if (cursor.moveToFirst()) {
do {
UserData userData = new UserData();
userData.setTodo(cursor.getString(1));
userData.setNote1(cursor.getString(2));
userData.setNote2(cursor.getString(3));
userData.setDuedate(cursor.getString(4));
userData.setDuetime(cursor.getString(5));
**userData.setTimestamp(cursor.getLong(6));**
modelList.add(0, userData);
} while (cursor.moveToNext());
...
ListAdapter.java file:
...
public void onBindViewHolder(final ListViewHolder holder, final int position) {
...
holder.cardBlankText5.setText((int) dbList.get(position).getTimestamp());
Activity.java file:
...
public void onClickSave(View v) {
...
long timestamp=System.currentTimeMillis();
helper = new DatabaseHelper(Activity.this);
helper.insertIntoDB(todo,note1,note2,duedate,duetime,timestamp);
startActivity(new Intent(Activity.this,ListActivity.class));
}
Having DBContract.DBEntry.COLUMN_NAME_TIMESTAMP as a DATETIME type should work. I usually have utility method that takes the cursor and column name and returns a Date object:
public static Date getDateColumn(Cursor c, String column) {
Date d = null;
Long time = c.getLong(c.getColumnIndexOrThrow(column));
if (time != null && time != 0) {
d = new Date();
d.setTime(time);
}
return d;
}
The second thing to check is whether or not that field is being asked for in your query. Sharing the value of query could shed some light, but usually you get things like this when the column you are asking for isn't in the projection.
e.g. select columnA, columnB from mytable; and then you try to get something from columnC which isn't in the results.
Don't try to get Long from column declared as TEXT. Declare it as INTEGER.
Or use getString() and convert value to Long.
Related
As the title, I am trying to update a specific data stored in SQLiteDatabase, but it updates every item in it.
What I am trying is making a note taking app. So far it saves what I want to save properly but when I try to edit a note, the problem comes.
It changes all the saved notes when I press the edit button, including the note I wanted to edit.
The note is defined as MemoItem object i.e. MemoItem memoItem = new MemoItem(), and has following variables: String savedTime, memo, and category.
When I tap the note I want to edit it takes saved values successfully but yeah.
And just in case it is needed, here are the things that are declared in my SQLiteOpenHelper class:
public class MemoListDbHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "MemoListDB.db";
public static class MemoEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_CATEGORY = "category";
public static final String COLUMN_SAVED_TIME = "savedTime";
public static final String COLUMN_MEMO = "memo";
}
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + MemoEntry.TABLE_NAME + " (" +
MemoEntry._ID + " INTEGER PRIMARY KEY," +
MemoEntry.COLUMN_CATEGORY + " TEXT," +
MemoEntry.COLUMN_SAVED_TIME + " TEXT," +
MemoEntry.COLUMN_MEMO + " TEXT )";
}
I made a updateNote() method inside the Helper Class:
public void updateNote(MemoItem memoItem) {
if (memoItem == null) {
return;
}
SQLiteDatabase db = getReadableDatabase();
ContentValues values = new ContentValues();
values.put(MemoEntry.COLUMN_MEMO, memoItem.memo);
db.update(MemoEntry.TABLE_NAME, values, "_id=" + MemoEntry._ID, null);
}
And the edit button is inside a Fragment called MemoFragment.
The overridden onClick method has another method named updateMemoOnClick() in it, which I made.
When the button is clicked it will make a new MemoItem object that has category, memo, and saved time that user put in and pass the object to updateNote() method above:
private void updateMemoOnClick() {
MemoItem memoItem = new MemoItem();
memoItem.memo = memoEditText.getText().toString();
memoItem.category = selectedBodyPartTextView.getText().toString();
memoItem.startedTime = startTimeTextView.getText().toString();
memoListDbHelper.updateMemo(memoItem);
}
Why is my SQLite update() updating all the items the database has?
Can anyone please help? I have been on this problem for the half of the day already. Thanks in advance!
Here you making the mistake
db.update(MemoEntry.TABLE_NAME, values, "_id=" + MemoEntry._ID, null);
replace MemoEntry._ID with your row id . like memoItem.id
db.update(MemoEntry.TABLE_NAME, values, "_id=" + [row id should be here], null);
You can try different way to update
db.update(MemoEntry.TABLE_NAME, values, "_id=?", new String[]
{String.valueOf(memoItem._ID)});
OR
db.update(MemoEntry.TABLE_NAME, values, "_id='" + memoItem._ID+"'", null);
I'm assuming that you are displaying the memo entries in a recycler view, so in order to do that you need many MemoEntry objects. You do not need the memoItem object.
You can retrieve the list of entries through a method like this:
public ArrayList<MemoEntry> getMemoEntries(SQLiteDatabase db){
ArrayList<MemoEntry> entries = new ArrayList<>();
Cursor c;
c = db.rawQuery("SELECT * FROM " + ENTRY_TABLE, null)
if(c != null && c.moveToFirst()){
while(!c.isAfterLast()){
MemoEntry entry = new MemoEntry();
entry.setId(c.getInt(c.getColumnIndex(Memo_Entry._ID)));
entry.setCategory(c.getString(c.getColumnIndex(Memo_Entry.COLUMN_CATEGORY)));
entry.setMemo(c.getString(c.getColumnIndex(Memo_Entry.COLUMN_MEMO)));
entries.add(entry);
c.moveToNext();
}
c.close();
}
return entries;
When you go to edit an entry you can reference the objects id field.
Then you can use the below query once the user saves.
db.RawQuery("UPDATE " + MemoEntry.TABLE_NAME + " SET " + MemoEntry.COLUMN_MEMO + " = " MemoEntry.memo + " WHERE " + MemoEntry.COLUMN_ID+ " = " + memoEntry._id ,null);
I think the confusion here is that you are putting column names within the MemoEntry object?
It might also be a good idea to update the saved time.
In Android SQLite, I am trying to get some details of customers when I am online, store it in SQLite database, and display them when I am offline.
Unfortunately when doing it so, that the order of the columns get unfortunately messed up.
I have the following table, TABLE_AGEING_VALUES_ALL:
Loan_No text primary key,
agreement_date date,
branch_name text,
loan_status text,
address1 text,
address2 text,
status_type integer,
user_id integer
The customer details are displayed like this when I am online:
Example 1:
Loan Number: CDAGRTW1412090016
Agreement Date: 12/9/2014 12:00:00 AM
Branch Name:
Loan Status: Expired
Address 1: 9/43, MOTI BAG NAGAL FATHORI YAMUNA BRIDGE
Address 2:
Unfortunately, when I am offline, the order of the fields get messed up like this.
Example 1:
Loan Number: CDAGRTW1412090016
Agreement Date:
Branch Name: 9/43, MOTI BAG NAGAL FATHORI YAMUNA BRIDGE
Loan Status:
Address 1: Expired
Address 2: 12/9/2014 12:00:00 AM
I would like to know why that it should ever happen so, at all.
Here is my update or insert function call in main activity fragment Java file, that depending upon if whether, within any given case that row already exists or not:
onResponse() function call:
if (db.selectAgeingvalues(Loan_No, status_type, user_id) == 0) {
db.insertAgeingvalues(Loan_No, agreement_date, branch_name, loan_status, address1, address2, status_type, user_id);
} else {
db.updateAgeingvalues(Loan_No, agreement_date, branch_name, loan_status, address1, address2, status_type, user_id);
}
Here is my select function call to retrieve details of customers from stored Android SQLite database table when I am offline:
onFailure() function call:
sqliteDB db = new sqliteDB(getActivity());
List<String> AgeingvaluesList[] = db.selectAgeingvalues("-1", user_id);
for(int i = 0; i < AgeingvaluesList[0].size(); i++)
{
Loan_No = AgeingvaluesList[0].get(i);
agreement_date = AgeingvaluesList[1].get(i);
branch_name = AgeingvaluesList[2].get(i);
loan_status = AgeingvaluesList[3].get(i);
address1 = AgeingvaluesList[4].get(i);
address2 = AgeingvaluesList[5].get(i);
status_type = AgeingvaluesList[6].get(i);
}
Here are my SELECT, INSERT, UPDATE, onCreate() and onUpgrade() function calls inside of my own declared sqliteDB.java Java file, as follows, as like, such as, those like:
onCreate(SQLiteDatabase sqLiteDatabase) function call
in order to be able to be creating a table TABLE_AGEING_VALUES_ALL into the stored Android SQLite database table if it already does not exist or dropping it and recreating it if it already exists, based upon following assigned values of variable, sqLiteDatabase:
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// TODO Auto-generated method stub
sqLiteDatabase.execSQL(
"create table " + TABLE_AGEING_VALUES_ALL +
"("
+ "Loan_No text not null unique primary key,"
+ "branch_name text,"
+ "address1 text not null,"
+ "address2 text,"
+ "loan_status text not null,"
+ "agreement_date text not null,"
+ "status_type number not null,"
+ "user_id text not null"
+ ")"
);
}
onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) function call
in order to be able to be upgrading a table TABLE_AGEING_VALUES_ALL into the stored Android SQLite database table if it already exists or not during upgradation of mobile application to a newer version or during uninstallation and reinstallation of mobile application to a newer version, based upon following assigned values of variables, sqLiteDatabase, i and i1:
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
// TODO Auto-generated method stub
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_AGEING_VALUES_ALL);
onCreate(sqLiteDatabase);
}
insertAgeingvalues(String Loan_No, String agreement_date, String branch_name, String loan_status, String address1, String address2, String status_type, String user_id) function call
in order to be able to be inserting a row into the stored Android SQLite database table if it already does not exist, based upon following assigned values of variables, Loan_No, agreement_date, branch_name, loan_status, address1, address2, status_type and user_id:
public boolean insertAgeingvalues(String Loan_No, String agreement_date, String branch_name, String loan_status, String address1, String address2, String status_type, String user_id)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("Loan_No", Loan_No);
contentValues.put("agreement_date", agreement_date);
contentValues.put("branch_name", branch_name);
contentValues.put("loan_status", loan_status);
contentValues.put("address1", address1);
contentValues.put("address2", address2);
contentValues.put("status_type", status_type);
contentValues.put("user_id", user_id);
db.insert(TABLE_AGEING_VALUES_ALL, null, contentValues);
return true;
}
updateAgeingvalues(String Loan_No, String agreement_date, String branch_name, String loan_status, String address1, String address2, String status_type, String user_id) function call:
in order to be able to be updating a row into the stored Android SQLite database table if it already exists, based upon following assigned values of variables, Loan_No, agreement_date, branch_name, loan_status, address1, address2, status_type and user_id:
public int updateAgeingvalues(String Loan_No, String agreement_date, String branch_name, String loan_status, String address1, String address2, String status_type, String user_id)
{
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("Loan_No", Loan_No);
contentValues.put("agreement_date", agreement_date);
contentValues.put("branch_name", branch_name);
contentValues.put("loan_status", loan_status);
contentValues.put("address1", address1);
contentValues.put("address2", address2);
contentValues.put("status_type", status_type);
contentValues.put("user_id", user_id);
// updating row
return db.update(TABLE_AGEING_VALUES_ALL, contentValues, "Loan_No = ? AND user_id = ?",
new String[] {Loan_No, user_id});
}
selectAgeingvalues(String Loan_No, String status_type, String user_id) function call
Android SQLite database table:
public int selectAgeingvalues(String Loan_No, String status_type, String user_id)
{
int count = 0;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor;
cursor = db.rawQuery("SELECT EXISTS(SELECT Loan_No FROM " + TABLE_AGEING_VALUES_ALL + " WHERE user_id = \"" + user_id + "\" AND Loan_No = \"" + Loan_No + "\" AND status_type = " + status_type + ")", null);
if (cursor.moveToFirst()) {
do {
count = Integer.parseInt(cursor.getString(0));
} while (cursor.moveToNext());
}
return count;
}
selectAgeingvalues(String status_type, String user_id) function call
in order to be able to be retrieving a row from the stored Android SQLite database table if it already exists or not, based upon following assigned values of variables, status_type and user_id:
public List<String>[] selectAgeingvalues(String status_type, String user_id)
{
String Loan_No;
String agreement_date;
String branch_name;
String loan_status;
String address1;
String address2;
List AgeingvaluesList[] = new List[7];
for(int i = 0; i <= 6; i++) {
AgeingvaluesList[i] = new ArrayList<String>();
}
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor;
cursor = db.rawQuery("SELECT * FROM "+TABLE_AGEING_VALUES_ALL+" WHERE user_id = \""+user_id+"\" AND status_type = "+status_type, null);
if (cursor.moveToFirst()) {
do {
Loan_No = cursor.getString(0);
AgeingvaluesList[0].add(Loan_No);
agreement_date = cursor.getString(1);
AgeingvaluesList[1].add(agreement_date);
branch_name = cursor.getString(2);
AgeingvaluesList[2].add(branch_name);
loan_status = cursor.getString(3);
AgeingvaluesList[3].add(loan_status);
address1 = cursor.getString(4);
AgeingvaluesList[4].add(address1);
address2 = cursor.getString(5);
AgeingvaluesList[5].add(address2);
status_type = cursor.getString(6);
AgeingvaluesList[6].add(status_type);
} while (cursor.moveToNext());
}
return AgeingvaluesList;
}
What am I doing wrongly enough?
Instead of cursor.getString(1); change it to cursor.getString(cursor.getColumnIndex("Loan_No ")); and do this for all the respective fields.
Always use column name instead of position, because column position can change.
of course column name can change as well but let say if you add a new column and it position between column 1 and column 2. You need to change your code if you use number. But if you use name, you will be fine.
(D.'s original answer, keeping it all for reference purposes only).
I think your problem is in the
for(int i = 0; i < AgeingvaluesList[0].size(); i++)
With this AgeingvaluesList[0].size(); you are only getting the size of the first element and that's also the size of the first element!
Change it to AgeingvaluesList().size();
also please would you mind instead of cursor.getString(1); change it to cursor.getString(cursor.getColumnIndex("Loan_No ")); and do this for all the respective fields
Currently i am developing Prototype of Air quality monitoring device using Arduino. The device integrated with three gas sensors that will send the the data over the HC-05 bluetooth module to my android app. I am able to receive the values in real time and display it using textview but have no idea on have to save the data in android device itself using SQL database. I have tried all tutorials that i found elsewhere but it only save data on a button click, but even when trying the buttonclick method the app crashes (instead i want to save the data continuously on the background,every time the app starts). I am very new to android development, please help me.
Currently i need to save (time/date, gps coordinate, sensor1 data, sensor2 data, sensor3 data, overall air quality).
I am sorry, already removed the SQL storing part, here the code for get real time data from Arduino.
//data received from Arduino as #data+data+data+~
bluetoothIn = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == handlerState) { //if message is what we want
String readMessage = (String) msg.obj; // msg.arg1 = bytes from connect thread
recDataString.append(readMessage); //keep appending to string until ~
int endOfLineIndex = recDataString.indexOf("~"); // determine the end-of-line
if (endOfLineIndex > 0) { // make sure there data before ~
String dataInPrint = recDataString.substring(0, endOfLineIndex);
if (recDataString.charAt(0) == '#') //if it starts with # we know it is what we are looking for
{
dataInPrint = dataInPrint.substring(1, dataInPrint.length() - 1); //remove the Hash tag symbol
StringTokenizer st = new StringTokenizer(dataInPrint,"+");
String sensor0 = st.nextToken();
String sensor1 = st.nextToken();
String sensor2 = st.nextToken();
showMq135.setText(sensor0); //update the textviews with sensor values
showMq9.setText(sensor1);
showDust.setText(sensor2);
p1 = (ProgressBar) findViewById(R.id.progressBarMq135);
int p135 = Integer.parseInt(sensor0);
p1.setMax(100);
p1.setProgress(p135);
p2 = (ProgressBar) findViewById(R.id.progressBarMq9);
int p9 = Integer.parseInt(sensor1);
p2.setMax(100);
p2.setProgress(p9);
p3 = (ProgressBar) findViewById(R.id.progressBarDust);
int pDust = Integer.parseInt(sensor2);
p3.setMax(100);
p3.setProgress(pDust);
if (p135 >= 51 || p9 >= 51 || pDust >= 51) {
showAirQuality.setTextColor(Color.RED);
showAirQuality.setText("Hazardous/Very unhealthy");
sound.start();
}
else {
showAirQuality.setTextColor(Color.BLUE);
showAirQuality.setText("Normal/Intermediate");
}
}
recDataString.delete(0, recDataString.length());//clear all string data
}
}
}
};
Ok here's something that you could adapt, it shows how to create database and table(s) and then how to insert data and also a how to do a check check that the data exists.
Virtually all of the code is in the SQLiteOpenHelp subclass, which for my convenience I have called so46375780DBHelper (you would very likely rename this) this should be in a file named so46375780DBHelper.java :-
public class so46375780DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "airquality";
public static final int DBVERSION = 1;
public static final String READINGS_TBL = "air_readings";
public static final String READINGID_COL = "_id";
public static final String READINGTIMESTAMP_COL = "timestamp";
public static final String READINGLOCATION_COL = "location";
public static final String READINGSENSOR1_COL = "sensor1";
public static final String READINGSENSOR2_COL = "sensor2";
public static final String READINGSENSOR3_COL = "sensor3";
public static final String READINGAIRQLTY_COL = "airquality";
SQLiteDatabase db;
// SQL to create the table
String tblcrtsql = "CREATE TABLE " + READINGS_TBL + "(" +
READINGID_COL + " INTEGER PRIMARY KEY, " + // unqiue identifier
READINGTIMESTAMP_COL + " INTEGER, " +
READINGLOCATION_COL + " TEXT, " +
READINGSENSOR1_COL + " TEXT, " +
READINGSENSOR2_COL + " TEXT, " +
READINGSENSOR3_COL + " TEXT, " +
READINGAIRQLTY_COL + " TEXT" +
")";
// Database Helper Constructor
so46375780DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
db = this.getWritableDatabase(); // Open the database
}
#Override
// Called when Database is openbed when it doesn't already exist
// ^^^^^^^^ IMPORTANT to note ^^^^^^^^
public void onCreate(SQLiteDatabase db) {
db.execSQL(tblcrtsql); // Create the table(s)
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversio) {
}
public boolean insertReading(String location,
String sensor1,
String sensor2,
String sensor3,
String airquality) {
ContentValues cv = new ContentValues();
cv.put(READINGTIMESTAMP_COL,
Long.toString(
System.currentTimeMillis()
)
);
cv.put(READINGLOCATION_COL,location);
cv.put(READINGSENSOR1_COL,sensor1);
cv.put(READINGSENSOR2_COL,sensor2);
cv.put(READINGSENSOR3_COL,sensor3);
cv.put(READINGAIRQLTY_COL,airquality);
return (db.insert(READINGS_TBL,null,cv) < 1);
}
public void showAllDataToLog() {
//get all rows eqv to SELECT * FROM air_readings;
Cursor csr = db.query(READINGS_TBL,null,null,null,null,null,null);
// Traverse the cursor
while (csr.moveToNext()) {
String rowinfo = "Row " +
csr.getPosition() +
" of " +
csr.getCount() + ".";
for (int i=0; i < csr.getColumnCount();i++) {
rowinfo = rowinfo +
"\n\t Column=" + csr.getColumnName(i) +
"\t Value=" + csr.getString(i);
}
Log.d("DBINFO",rowinfo);
}
csr.close(); // Should always close cursor when finished with them
}
}
In brief you have the
class variable declarations,
the contructor
overidden methods onCreate and onUpgrade (both required, but not necessarily required to do anything)
insertReadings method that uses the SQLite update method, which utilises a ContentValues object for the column/value pairs. This method will return a value of 1 or greater (the rowid which equates to the _id column), if the insert was successful.
showAllDataToLog just there to check the data exists.
Next it's just a matter of 2 steps to enable insertion of data, these steps are placed in the class (or classes) where the data will be inserted.
1 Create an instance of the SQLiteOpenHelper subclass e.g. :-
so46375780DBHelper dbhlpr = new so46375780DBHelper(this);
2 Use the insertReading method to insert some data e.g. :-
// Insert a row
dbhlpr.insertReading(
"001,345", //coords
"76.5", // sensor 1 reading
"57.3", // sensor 2 reading
"12.6", // sensor 2 reading
"LOUSY" // air quality
);
Note! made up readings, also you may wish to alter the method to utilise more relevant types (note SQlite is extremely flexible with types, with few limitations you can store any type if value in any type of column). However, when it comes to extracting the data from a Cursor you should chose the most appropriate get????? method (below only the getString method is used which is Ok for just checking the existence).
The following code will list the data to the log, it is only intended for initial re-assurance that the inserts are working :-
// Check data (writes to the log)
dbhlpr.showAllDataToLog();
I have the following code in a bigger project:
final class DBlifetimeStatisticsHandler{ //implements DBvalueHandler<Cyclist, Double>{
private final String TAG = getClass().getName();
private static final boolean debug = true;
private final DBminMaxAvgHandler dbMinMaxAvgHandler = new DBminMaxAvgHandler();
// table name
private static final String TABLE_LIFETIME_STATISTICS = "lifetime_statistics";
// column names
private static final String KEY_LIFETIME_STATISTICS_ID = "lifetime_statistics_id";
private static final String KEY_MIN_MAX_AVG = "min_max_avg";
// table create statement
private static final String CREATE_TABLE = "CREATE TABLE "
+ TABLE_LIFETIME_STATISTICS + "("
+ KEY_LIFETIME_STATISTICS_ID + " LONG PRIMARY KEY NOT NULL,"
+ KEY_MIN_MAX_AVG + " LONG"
+ ")";
public void onCreateTable(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
public void onUpgrade(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LIFETIME_STATISTICS);
onCreateTable(db);
}
public long addValue(SQLiteDatabase db, Statistics Statistics ) {
ContentValues values = new ContentValues();
long ID = getLatestID(db)+1;
values.put(KEY_STATISTICS_ID, ID);
... //not important to the question
}
private long getLatestID(SQLiteDatabase db){
String selectQuery = "SELECT MAX(" + KEY_STATISTICS_ID +") FROM " + TABLE_STATISTICS;
Cursor c = db.rawQuery(selectQuery, null);
c.moveToFirst();
int id = 0;
Log.e("count", String.valueOf(c.getCount()));
if (c.moveToFirst()){
...
}
return id;
}
}
After I updated the table it is created again. So when I try to add a new value I had problems cause it always jumped into the if clause because c.moveToFirst() always returned true.
So I tried to tried to check if c.getCount() would return true but sadly it does always return 1. So the question is: Why would it return 1 on an empty table? (I do use Questoid SQLite Browser and the table is really empty)
You use aggregate function MAX, so read documentation:
There are two types of simple SELECT statement - aggregate and non-aggregate queries. A simple SELECT statement is an aggregate query if it contains either a GROUP BY clause or one or more aggregate functions in the result-set.
An aggregate query without a GROUP BY clause always returns exactly one row of data, even if there are zero rows of input data.
It might be some kind of a buggy behavior when using MAX. Check this link too Android database (SQLite) returns a non-empty cursor from an empty table
this is my solution
public Boolean isNotEmpty(){
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_STATISTICS, null);
while (cursor.moveToNext() ) {
return true;
}
return false;
}
You are getting a result with one row in your Cursor because that is what you requested.
The result is a single column called MAX with a value that will be the max id of all the rows in your table. In your case of an empty table, this value is null.
I am using group by to resolve this. Please check my example :
SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE isSynced=0 group by isSynced
I resolve this probme this way:
SELECT COUNT(*) AS numero, MAX(tagua_lagps) as tmp_max_lagps, MAX(tagua_logps) as tmp_max_logps, MIN(tagua_lagps) as tmp_min_lagps, MIN(tagua_logps) as tmp_min_logps FROM TAB_AGUA
On empty table, c.getCount(); gives 1 but values are NULL. But numero (c.getString(c.getColumnIndex("numero")) has a value of 0.
So rather than checking c.getCount() you must check the result of count(*).
public boolean findContact(String phoneNumber) {
boolean exists = false;
Cursor mCursor = mDb.rawQuery("SELECT * FROM " + SQLITE_TABLE + " WHERE " + KEY_PHONENUMBER + " = " + phoneNumber, null);
if (mCursor.moveToFirst()) {
exists = true;
} else exists = false;
return exists;
}
It is supose to return true when a row with telephone number exists (format is +441212312312 - String ). The problem is that it always return false, even if such a row exists. I think that a problem is with WHERE clause, but LIKE don't work either. How can I do this ?
thanks for your response
i suggest you that use query, insert, update or delete clauses directly from SQLiteDatabase object instance ;)
And see link below to know which values you will have returned
SQLiteDatabase Object
And i suggest too that if you just want if it exists don't ask about * ... ask about _id because it's primary key it has a index ;)) <-- it means faster
Here i seek a specific row:
public Cursor getEnvio(final String empresa_p, final String albaran_p) {
return db.query(Envio.KEY_ENVIO, new String[] { Envio.KEY_ID,
Envio.KEY_ALBARAN, Envio.KEY_LINEA, Envio.KEY_TIPO,
Envio.KEY_DESTINATARIO, Envio.KEY_DIR, Envio.KEY_POBLACION,
Envio.KEY_POBLACION, Envio.KEY_PRIORIDAD, Envio.KEY_INCIDENCIA,
Envio.KEY_EMP, Envio.KEY_CPOSTAL }, Envio.KEY_EMP + " = ? AND "
+ Envio.KEY_ALBARAN + " = ? ", new String[] { empresa_p,
albaran_p }, null, null, Envio.KEY_LINEA);
}