I am trying to update the field of an entry in an SQLiteDatabase using the db.update(...) method, but it seems the value is not stored. I've tried the convenience db.query(...) method right after the update method has been executed and found that the entry is still stored as before the update.
Is there some sort of background work that I must wait for before the query, or where am I going wrong? I am using a singleton extended SQLiteOpenHelper (dbHelper) as recommended in SQLite DB accessed from multiple threads and I've even tried getting a new readable instance of the db from the helper for the query in a new thread, as in the code below:
ContentValues deviceListEntry = new ContentValues();
deviceListEntry.put(DeviceListDBEntry.NODE_ID, nodeID);
...
...
String WHERE = DeviceListDBEntry.NODE_ID + " = ?";
final String[] WHERE_ARG = {String.valueOf(nodeID)};
SQLiteDatabase db = dbHelper.getWritableDatabase();
int listings = 0;
try {
//Update the device in the database DeviceList table
listings = db.update(
DeviceListDBEntry.TABLE_NAME,
deviceListEntry,
WHERE,
WHERE_ARG
);
} catch (Exception e) {
throw new ApiHandlerException("db.update(DeviceList, node " + nodeID + ")", e);
}
Log.e("updateDBdevice", " node " + device.getNodeID() + " listening = " + device.isListening());
final String[] TABLE_COLUMNS = {
DeviceListDBEntry.DEVICE_TYPE,
DeviceListDBEntry.INTERVIEWED,
DeviceListDBEntry.DEVICE_JSON
};
final String where = WHERE;
new Thread(new Runnable() {
#Override
public void run() {
SQLiteDatabase db2 = dbHelper.getReadableDatabase();
Cursor deviceEntry = db2.query(
DeviceListDBEntry.TABLE_NAME, //FROM DeviceList Table
TABLE_COLUMNS, //SELECT * columns
where, //WHERE nodeID =
WHERE_ARG, //args nodeID
null,
null,
null
);
if (!deviceEntry.moveToFirst()) throw new ApiHandlerException("DeviceListDB no entry found - WHERE nodeID = " + nodeID);
if (deviceEntry.getCount() > 1) throw new ApiHandlerException("DeviceListDB duplicate entries - WHERE nodeID = " + nodeID);
String deviceJson = deviceEntry.getString(deviceEntry.getColumnIndexOrThrow(DeviceListDBEntry.DEVICE_JSON));
Log.e("updateDBdevice retreive", " node " + nodeID + " JSON : " + deviceJson);
}
}).start();
I am using a Gson object to parse my device class to a JSON object which is stored in the DB. I know that this works when using the db.insert(...) method.
The query here is only there to see if the update was successful, because I found that explicit queries using other delayed threads (synchronised using a object lock and the same SQLiteOpenHelper) returned values that were not updated.
Is there an obvious thing I am missing or should I consider going to raw SQL commands on the db?
My mistake, I found that I had actually not added the updated JSON object to the new entry. Subsequently the deviceJson column of the listing did not update, but a db.update() was executed...
If "WHERE" clause has "text" column comparison then use single quotes around value. In your case try below line (notice single quotes around ?)
String WHERE = DeviceListDBEntry.NODE_ID + " = '?'";
Related
I have a list of objects provided by another service which I use to update my own data. When I try to use NamedParameterJdbcTemplate.batchUpdate, all returned values are zero.
public void updateWeather(List<Weather> weatherList) {
String query = "UPDATE weather \n" +
"SET rain_probability = ROUND(:rainProbability, 4), \n" +
"wind_speed = :windSpeed \n" +
"WHERE city_id = :cityId AND date = :date;";
List<MapSqlParameterSource> batchList = new ArrayList<>();
for(Weather weather : weatherList) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("rainProbability", weather.getRainProbability());
params.addValue("windSpeed", weather.getWindSpeed());
params.addValue("cityId", weather.getCityId());
params.addValue("date", weather.getDate());
batchList.add(params);
}
this.namedParameterJdbcParameter
.batchUpdate(query, batchList.toArray(new MapSqlParameterSource[] {});
}
If I run this UPDATE directly in the database, it works fine. Futhermore, if I run it one by one, that is, replacing values (instead of adding the parameter source to batchList) it also works.
For example:
for (Weather weather : weatherList) {
String query = String.format("UPDATE weather \n" +
"SET rain_probability = ROUND('%d', 4), \n" +
" wind_speed = %d \n" +
" WHERE city_id = :cityId AND date = :date;",
weather.getRainProbability(),
weather.getWindSpeed(),
weather.getCityId(),
weather.getDate()
);
this.namedParameterJdbcTemplate.update(query, Collections.emptyMap());
}
Any suggestions of what I'm doing wrong?
Is it the use of "\n" or the ";" at the end of the statement within the String? (I'm surprised you don't get a SQL Syntax exception with the ; inside the actual query string)
Also dates are always a bit tricky and if that isn't converting properly then your WHERE clause isn't going to match and is possibly why 0 rows are returned. Could you temporarily try converting dates to Strings and see if the count is correct (e.g. for Oracle: AND date = TO_DATE(:dateStr, 'DD/MM/YYYY') )
I am going nuts over here. I have been trying to update one column in one row inside of my SQLite Database but its just not happening regardless of what I try.The value is never updated and there are no exceptions in my log.
The below code might summarise my problem best.
the updateLatestMessage() function is part of a Database Controller Class.
public void updateLatestMessage(int messageID, int chatID){
Log.d("DB", "message ID =" + messageID); //example output = 125
Log.d("DB", "chat ID =" + chatID); //example output = 2
SQLiteDatabase db = this.getWritableDatabase();
try {
ContentValues cv = new ContentValues();
cv.put("latest_message_id", messageID);
db.update("chat", cv, "chat_id = ?" + chatID, null);
db.close();
//db.update(tableChat.TABLE_NAME, cv, tableChat.getChatId() + " = ?", new String[]{String.valueOf(chatID)}); // tried this before didn't work either
}
catch(Exception e) {
Log.d("DB", "Error: "+e.toString());
}
}
currently latest message has the ID of 5
myDB.chat.updateLatestMessage((int) messageID, globalChatID);//calling the above DB update code
after running this code the latest message still has the id of 5 instead of 125
I am expecting the messageID to be updated inside of the the latest_message_id column inside my already existing chat row.
If the name of the table is "chat", the name of the column in the WHERE clause is "chat_id" and the argument of WHERE clause is chatID, then the recommended way for the update is this:
int result = db.update("chat", cv, "chat_id = ?", new String[]{String.ValueOf(chatID)});
Check the value of result after the statement.
If its value is greater than 0 then the update was successful.
I've searched all around the web for a similar question as what i want but i couldn't find any.
So, I made an app where i get news data from JSON and display it in a list, it's all good, but now i want to add something to it, when there is no internet connection i want to display the latest list viewed. to do this i thought of storing the JSON arraylist in a databases and update it whenever the news change while there's a connection so when there's no connection it'll display the data in the database.
the thing is I'm kind of lost on how to do this..
I made a java class called NewsDBHelper where i create my database and table.
public class NewsDBHelper extends SQLiteOpenHelper {
public static final String LOG_TAG = NewsDBHelper.class.getSimpleName();
private static final String DATABASE_NAME = "news.db";
private static final int DATABASE_VERSION = 1;
public NewsDBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String SQL_CREATE_PRODUCTS_TABLE = "CREATE TABLE " + Contract.NewsEntry.TABLE_NAME + " ("
+ Contract.NewsEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ Contract.NewsEntry.COLUMN_SECTION + " TEXT NOT NULL, "
+ Contract.NewsEntry.COLUMN_TITLE + " TEXT NOT NULL, "
+ Contract.NewsEntry.COLUMN_DATE + " BLOB, "
+ Contract.NewsEntry.COLUMN_AUTHOR + " TEXT DEFAULT NULL, "
+ Contract.NewsEntry.COLUMN_URL + " BLOB);";
Log.v(LOG_TAG,SQL_CREATE_PRODUCTS_TABLE);
db.execSQL(SQL_CREATE_PRODUCTS_TABLE);
}
Then in my mind the idea is when the JSON data are stored in an array, i'd take the array values and store them in the table.
private static List<News> extractFeatureFromJson(String newsJSON) {
if (TextUtils.isEmpty(newsJSON)) {
return null;
}
List<News> news = new ArrayList<>();
try {
JSONObject baseJsonResponse = new JSONObject(newsJSON);
String response = baseJsonResponse.getString("response");
JSONObject object = new JSONObject(response);
;
JSONArray newsArray = object.getJSONArray("results");
for (int i = 0; i < newsArray.length(); i++) {
JSONObject currentNews = newsArray.getJSONObject(i);
String title = currentNews.getString("webTitle");
String section = currentNews.getString("sectionName");
String date = currentNews.getString("webPublicationDate");
JSONArray tag = currentNews.getJSONArray("tags");
String author = null;
if (tag.length() != 0) {
author = tag.getJSONObject(0).getString("firstName");
}
String url = currentNews.getString("webUrl");
News nNews = new News(title, date, section, author, url);
news.add(nNews);
//add news array in the table
}
} catch (JSONException e) {
Log.e("QueryUtils", "Problem parsing the news JSON results", e);
}
return news;
}
i don't really know how to do this or if it's possible even. if it is how can i do it? or what's the best way to implement my idea?
you're are 70% done with what you're trying to do.
All you need to do now is:
Get a writable database from the NewsDBHelper
Create a content values of the data you want to insert to db
Call the insert() method on the writable database, passing it the content values.
And fetching the persisted data from the database at due time.
Below is a sample code that adopts the above listed steps.
//Create an instance of NewsDBHelper
NewsDBHelper newsDBHelper = new NewsDBHelper(context);
//get a writable database from newsDBHelper
SQLiteDatabase writableDatabase = newsDBHelper.getWritableDatabase();
//create content values of data to persist
ContentValues values = new ContentValues();
values.put("section","Sample section");
values.put("title","Sample title");
values.put("date","1/29/2018");
values.put("author","John Chan");
values.put("url","https://example.com");
//write the data to the database. Notice that the "news" is the table name
writableDatabase.insert("news",null,values);
To fetch data from the database, get a readable database from the newsDBHelper like this:
SQLiteDatabase readableDatabase = newsDBHelper.getReadableDatabase();
//query or read data from the database by calling:
readableDatabase.query(String table, String[] columns, String selection,
String[] selectionArgs,String groupBy, String having,
String orderBy, String limit);
For more information on SQLiteOpenHelper, Readable, and Writable Databases, check out the official the documentation of SQLiteDatabase
I have an SQLite Database in my android application with the following structure:
public void onCreate(SQLiteDatabase db) {
String CREATE_LISTS_TABLE = "CREATE TABLE " + TABLE_LISTS +
"("+
_ID + " INTEGER PRIMARY KEY , " +
NOTE + " TEXT" +
")";
db.execSQL(CREATE_LISTS_TABLE);
}
And this works, in that I can insert data into it without a problem. However I need to store the notes inside an array. I currently have the following query:
public List<String> getAllNotes() {
List<String> notes = new ArrayList<>();
String GET_ALL_NOTES = "SELECT * FROM " + TABLE_LISTS;
SQLiteDatabase db = getReadableDatabase();
if(db!=null)
{
Cursor cursor = db.rawQuery(GET_ALL_NOTES, null);
cursor.moveToFirst();
while(!cursor.isAfterLast())
{
notes.add(String.valueOf(cursor.getInt(cursor.getColumnIndex("notes"))));
cursor.moveToNext();
}
cursor.close();
}
db.close();
return notes;
}
However, this gives the following error:
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
I was wondering how to fix this, I have read the android developer stuff but I can't seem to get anything to work.
Thanks in advance
Check the value of "NOTE", and use it in:
notes.add(String.valueOf(cursor.getInt(cursor.getColumnIndex(NOTE))));
I think a best way to make the call should be something like this:
// Check the cursor
if(cursor != null) {
if (cursor.moveToFirst()) {
// Variables to be used
String note;
// Col position
int colNote = cursor.getColumnIndex(NOTE);
do {
// Get the information
note = cursor.getString(colNote);
// Add the note
notes.add(note);
} while (cursor.moveToNext());
}
// Close the cursor
cursor.close();
}
Because you are fetching only integer and string from database, instead of using ArrayList , you can try using HashMap. So you can get the value by just giving the key. Below simple code will work for ArrayList too with minor changes..
Try this
HashMap<Integer,String> notes = new HashMap<Integer,String>() ;
Cursor cursor = db.rawQuery(GET_ALL_NOTES, null);
while (cursor.moveToNext())
{
int i = cursor.getInt(0);
String s = cursor.getString(1);
notes.put (i,s) ;
}
cursor.close();
I currently I have my database set up like the following:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_LOCKERNUMBER
+ " TEXT NOT NULL, " + KEY_STATUS + " INTEGER, " + KEY_PIN
+ " INTEGER);");
And I am trying to write a method to get the pin code from the column for a specific locker number. Any ideas? I am very new I would like think I would need to use the query function and a cursor. I just one to get the integer value and store it into an int variable so I can compare the pin codes from what the user types in to the one in the database.
Queries to database returns in a Cursor object. You should use the db.query() method to get a row(s). Pass the table name, an array of columns you want to get (or null if you want all of them), pass a selection string that should be like "id = ?" or "key > ?", etc, then pass a String array containing the value for those ? inside the previous string,
and finally pass null for having, groupBy and orderBy unless you want to use them.
Cursor cursor = db.query(TABLE_NAME, new String[] { KEY_ROWID }, "id = ?", new String[] { Integer.toString(id) }, null, null, null);
After you get the Cursor, do cursor.moveToFirst() or cursor.moveToPosition(0) (can't remember the exact method, but the point is to move the cursor to the first retrieved row)
then you're going to iterate through the cursor with
while(cursor.moveToNext()) {
int keyRowIdColumnIndex = cursor.getColumnIndex(KEY_ROWID);
int yourValue = cursor.getInt(keyRowIdColumnIndex);
int keyLockNumberColumnIndex = cursor.getColumnIndex(KEY_LOCKNUMBER);
int pin = cursor.getInt(keyLockNumberColumnIndex);
}
This is a pretty straight forward task and there is a bunch of tutorials, examples, similar questions on SO:
How to perform an SQLite query within an Android application?
In general - you need to query the database passing your search arguments. See the documentation.
It will return you a Cursor with the matching results, which you can then iterate over and manipulate as you wish.
Fyi - storing password in a database table is a bad idea. On Android databases can be accessed and easily read. You either need to encrypt your data or think of another way to store it if it's important.
//Try This code
public String getLabeId(String LockNo)
{
ArrayList<String> Key_Pin_array = new ArrayList<String>();
Cursor cur = db.rawQuery("SELECT * FROM DATABASE_TABLE where KEY_LOCKERNUMBER = '" + LockNo + "'", null);
try {
while (cur.moveToNext())
{
System.out.println("Key_Pin" + cur.getString(3));
Key_Pin_array.add(cur.getString(3));
}
}
catch (Exception e)
{
System.out.println("error in getLabelID in DB() :" + e);
}
finally
{
cur.close();
}
return id;
}