I have a database which is calling Medicine, there are four columns in it: id (primary key autoincrement), dId (foreign key), Name and Time. I try to add new row using insert function. This function must return id of this adding. But when I check this from debugger, I see that it returned -1.
Code:
ContentValues values = new ContentValues();
values.put("RECIPE_ID", recipeId);
values.put("MED_NAME", etMedName.getText().toString());
values.put("MED_TIME", etMedTime.getText().toString());
long mid = sqdb.insert("Medicine", null, values);
use
long mid = 0;
try
{
mid = sqdb.insertOrThrow("Medicine", null, values);
}
catch(SQLException e)
{
// Sep 12, 2013 6:50:17 AM
Log.e("Exception","SQLException"+String.valueOf(e.getMessage()));
e.printStackTrace();
}
It will tell you the probable Exception
Related
I am facing challenge where i am unable to insert new record into table, rather it overwrites the first record in the table.
This happens in the physical device where as it is working fine in the emulator.
Following is the code used to insert the record:
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss", Locale.getDefault());
String strDate = formatter.format(date);
//SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING);
SQLiteDatabase db = this.getWritableDatabase();
/*ContentValues values = new ContentValues();
//values.put("UserId",1);
values.put("NoQPassed", scoreValues.get("NoPassed"));
values.put("NoQFailed", scoreValues.get("NoFailed"));
values.put("NoQSkipped", scoreValues.get("NoSkipped"));
values.put("SubjectName", scoreValues.get("strSubjectName"));
values.put("CompletedDateTime", strDate);
intRetVal= db.insert(score_Table_Name, null, values);*/
String strQuery="insert into "+score_Table_Name+" values ('"+strDate+"','"+scoreValues.get("NoPassed")+
"','"+scoreValues.get("NoFailed")+"','"+scoreValues.get("NoSkipped")+"','"+scoreValues.get("strSubjectName")+"')";
db.execSQL(strQuery);
db.close();
Tried inserting using db.insert and db.executeSQL, but none help. Can someone help me where i am going wrong?
I didnt add any primary key or autoincrement key to make sure the conflict is not because of that column. Do we always need to have primary key to insert new record?
you can use below getCount() method to count occurrences. if getCount(name)== 0 then do inserting. otherwise not inserting and try to log.
public int getCount(String name) {
Cursor c = null;
try {
db = Dbhelper.getReadableDatabase();
String query = "select count(*) from TableName where name = ?";
c = db.rawQuery(query, new String[] {name});
if (c.moveToFirst()) {
return c.getInt(0);
}
return 0;
}
finally {
if (c != null) {
c.close();
}
if (db != null) {
db.close();
}
}
}
But this logic may not be valid if you say you override it. I think there is no override possibilities in that android sqlite. Please check you might be drop your database any where before inserting new record. It may seems like override data
How can i get the autoincrement value in thansaction body?
Code
public void insertAllStudents(List<Student> students) {
String sql = "INSERT INTO "+ StudentEntry.TABLE_NAME +" VALUES (?,?,?,?,?);";
SQLiteDatabase db = this.getWritableDatabase();
SQLiteStatement statement = db.compileStatement(sql);
db.beginTransaction();
for (Student student: students) {
statement.clearBindings();
statement.bindString(2, student.getId());
statement.bindString(3, student.getFirstName());
statement.bindString(4, student.getLastName());
statement.bindLong(5, student.getBirthday());
statement.execute();
}
db.setTransactionSuccessful();
db.endTransaction();
}
The first column (_ID) is autoincrement field. Is it opportunity to get this value?
student.getId() -that's not id from database, that's different id.
If you change your code to use db.insert(), this method returns the id of the inserted row - see Get generated id after insert.
There is also a specialised SQLite function to get the last inserted row if you'd prefer to keep compiling statements, see Best way to get the ID of the last inserted row on SQLite
edit: example using db.insert(). This isn't tested but should be pretty close to functional.
db.beginTransaction();
boolean success = true;
final ContentValues values = new ContentValues();
for (final Student student: students) {
values.put("student_id", student.getId());
values.put("first_name", student.getFirstName());
values.put("last_name", student.getLastName());
values.put("birthday", student.getBirthday());
final long id = db.insert("my_table", null, values);
if (id == -1) {
success = false;
break;
}
// TODO do your thing with id here.
}
if (success) {
db.setTransactionSuccessful();
}
db.endTransaction();
Instead of statement.execute(), you can do statement.executeInsert(). This returns the row ID of the inserted row. Or, as #Tom suggested, you can use db.insert() instead, and it will also return the inserted row ID. Using a compiled statement like you are doing now is faster though.
If you want to try the db.insert() approach, it would look something like this:
ContentValues values = new ContentValues();
for (Student student: students) {
// use whatever constants you have for column names instead of these:
values.put(COLUMN_STUDENT_ID, student.getId());
values.put(COLUMN_STUDENT_FIRSTNAME, student.getFirstName());
values.put(COLUMN_STUDENT_LASTNAME, student.getLastName());
values.put(COLUMN_STUDENT_BIRTHDAY, student.getBirthday());
db.insert(StudentEntry.TABLE_NAME, null, values);
}
I have the following insert statement in my app which work.
Before the insert I want to first check the database if the value name does not exist in the name column.
If it does not exists I want to continue with the insert, else display an error message.
How do I incorporate it into my existing statement below?
public void insert(HashMap<String, String> queryValues){
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
Cursor c = database.query("SELECT * FROM user_details where" + "name=?", new String[] {values.put("name") });
if (c.getCount() > 0) {
// don't do it
return;
}
else {
values.put("name", queryValues.get("name"));
values.put("age", queryValues.get("age"));
database.insert("user", null, values);
}
database.close();
}
The correct way to do this is to add a unique constraint on the name field, and then use insertWithOnConflict() with a last argument of CONFLICT_FAIL. That's actually the default behavior. Your insert will fail if it would otherwise cause a constraint violation (insert() will return -1).
If you don't want to do that, there's no magic. Query your DB for a row with the given name field. If you are returned >0 rows, don't perform the insert.
Cursor c = db.query(..., "name=?", new String[] {theName}, ...);
if (c.getCount > 0) {
// don't do it
return;
}
I am using transactions to insert record to my database. Can you please tell me whether this is the right way to get total inserted record (return by numrow)? Also, in the code below, if some insert fails, will it continue to next insertion or will exit (I didn't use endTransaction in Catch block)?
int numrow = 0;
try{
db.beginTransaction();
for(mylibman cn : insertlist){
ContentValues values = new ContentValues();
values.put(KEY_LIBID, cn.getLibid());
values.put(KEY_NAME, cn.getBookname());
db.insertWithOnConflict(TABLE_NAME, null, values,SQLiteDatabase.CONFLICT_IGNORE);
numrow++;
}
db.setTransactionSuccessful();
}catch (Exception e) {
} finally {
db.endTransaction();
}
return numrow;
you should check like this
int numrow = 0;
try{
db.beginTransaction();
for(mylibman cn : insertlist){
ContentValues values = new ContentValues();
values.put(KEY_LIBID, cn.getLibid());
values.put(KEY_NAME, cn.getBookname());
//do like this
long insertedId=db.insertWithOnConflict(TABLE_NAME, null, values,SQLiteDatabase.CONFLICT_IGNORE);
if(insertedId!=-1)
{
numrow++;
}
}
db.setTransactionSuccessful();
}catch (Exception e) {
} finally {
db.endTransaction();
}
return numrow;
Your code will also count records that were ignored.
insertWithOnConflict returns the rowid of the inserted record, or -1, so you have to check for that:
if (db.insertWithOnConflict(TABLE_NAME, null, values,
SQLiteDatabase.CONFLICT_IGNORE) != -1)
numrow++;
The insertWithOnConflict function does not throw an exception if a record is not inserted due to a conflict. However, it will throw if there is some other error, such as an unknown column name, or a read-only database.
You should not blindly ignore exceptions; just use try/finally:
db.beginTransaction();
try {
for (...) {
...
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Non of the answers here reflect the documentation:
"returns:
the row ID of the newly inserted row OR the primary key of the existing row if the input param 'conflictAlgorithm' = CONFLICT_IGNORE OR -1 if any error"
Since the author wants to know the 'inserted' columns, both answers are wrong. The number inserted rows could be 0, as they already exist. However "CONFLICT_IGNORE" will make insert return the existing primary key, so the numrow will be the rows you 'tried' to insert and didn't fail, but not the rows 'inserted'.
You might have to use the flag "SQLiteDatabase.CONFLICT_ABORT" or "SQLiteDatabase.CONFLICT_FAIL" depending on what and how you insert.
Source: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insertWithOnConflict%28java.lang.String,%20java.lang.String,%20android.content.ContentValues,%20int%29
im trying to do a batch insert of about 700 floats. The method i'm using is below and as well as the content provider's bulkInsert. The issue is that when i put all the floating point values into the ContentValues nothing happens. What's a better way to insert those floating point values into the ContentValues object?
private void saveToDatabase( float[] tempValues )
{
ContentValues values = new ContentValues();
// WM: TODO: add patient id and sensor type
for (float tempVal : tempValues){
values.put( DataTable.COLUMN_DATA, tempVal );
}
ContentValues[] cvArray = new ContentValues[1];
cvArray[0] = values;
ContentResolver resolver = getContentResolver();
resolver.bulkInsert( HealthDevContentProvider.CONTENT_URI_DATA, cvArray);
public int bulkInsert(Uri uri, ContentValues[] values){
int numInserted = 0;
String table = null;
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case RAWINPUT_TABLE:
table = RAWINPUT_TABLE_PATH;
break;
}
db.beginTransaction();
try {
for (ContentValues cv : values) {
long newID = db.insertOrThrow(table, null, cv);
if (newID <= 0) {
throw new SQLException("Failed to insert row into " + uri);
}
}
db.setTransactionSuccessful();
getContext().getContentResolver().notifyChange(uri, null);
numInserted = values.length;
} finally {
db.endTransaction();
}
return numInserted;
}
If you want each float to have it's own record in your database, you need an instance of ContentValues for each new record. Right now you have one instance of ContentValues and you are writing the same key to it (meaning you are writing over the value) 700 times.
private void saveToDatabase( float[] tempValues ) {
final int count = tempValues.legnth;
ContentValues[] cvArray = new ContentValues[count];
for (int i = 0; i < count; i++) {
float tempVal = tempValues[i];
ContentValues values = new ContentValues();
values.put( DataTable.COLUMN_DATA, tempVal );
cvArray[i] = values;
}
/* all the rest */
}
I know that this will be rude, but just throw away this code. Providers have primary methods to deal with most SQLite operations and you tried to blend three of them (insert(), bulkInsert(), and applyBatch()) into some kind of Frankenstein. Here are the main mistakes:
1) This line values.put(DataTable.COLUMN_DATA, tempVal) is not inserting new entries at each iteration; it is overriding them. After all iterations, values contains only the 700th float value of your array.
2) As #Karakuri remembered, there is only one ContentValues instance inside cvArray. bulkInsert() doc states about its second parameter:
An array of sets of column_name/value pairs to add to the database. This must not be null.
So cvArray must contain a ContentValues instance (a set) for every entry you want to insert into the database.
3) Not exactly an error, but something you should watch out. There are no guarantees that mTables will exist, and trying to make operations without specifying a table will throw a SQLException.
4) These three lines are basically useless:
if (newId <= 0) {
throw new SQLException("Failed to insert row into " + uri);
}
insertOrThrow() already throws an exception if some error happens during the insert operation. If you want to check manually for an error, try insert() or insertWithOnConflict() (or add a catch to your try block and deal with the exception there).
5) And finally, there is the problem about numInserted #petey pointed (and there's no need to repeat).
One last advice: forget that bulkInsert() exists. I know that this will require more lines of code, but using applyBatch() you can achieve better results (and more easily, since you do not have to implement it). Wolfram Rittmeyer wrote a series of excellent articles about transactions, check if you have any doubt.
Last but not least (yes, I'm in a good mood today), this is how I would do a basic implementation of your code:
#Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db // TODO: retrieve writable database
final int match = matcher.match(uri);
switch(match) {
case RAWINPUT_TABLE:
long id = db.insert(RAWINPUT_TABLE, null, values); // TODO: add catch block to deal.
getContext().getContentResolver().notifyChange(uri, null, false);
return ContentUris.withAppendedId(uri, id);
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
private void saveToDatabase( float[] tempValues ) {
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
for (float tempVal : tempValues){
operations.add(ContentProviderOperation
.newInsert(HealthDevContentProvider.CONTENT_URI_DATA)
.withValue(DataTable.COLUMN_DATA, tempVal).build();
.withValue() // TODO: add patient id
.withValue() // TODO: add sensor type);
}
// WARNING!! Provider operations (except query if you are using loaders) happen by default in the main thread!!
getContentResolver().applyBatch(operations);
}
I use batch inserts, not sure what the difference between bulk and batch is but all I do is this
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
for(int j=0;j<locationAry.length;j++){
ContentValues values2 = new ContentValues();
values2.put(MapPoints.ELEMENT_ECM2ID, ecm2id);
values2.put(MapPoints.ELEMENT_ID, newElementId);
values2.put(MapPoints.LATITUDE, locationAry[j+1]);
values2.put(MapPoints.LONGITUDE, locationAry[j]);
values2.put(MapPoints.LAYER_ID, layerID);
operations2.add(ContentProviderOperation.newInsert(MapPoints.CONTENT_URI).withValues(values2).build());
}
getContentResolver().applyBatch(MapElements.AUTHORITY, operations);
did you override the bulkInsert method in your ContentProvider?
If one insert fails, your whole transaction fails. Without seeing your table create statement for unique keys, try a replace after your insert fails.. Also your numInserted will always be the same as values.length no matter what insert/replace fails. this doesnt seem correct either.
...
db.beginTransaction();
int numInserted = 0;
try {
for (ContentValues cv : values) {
long newID;
try {
newID = database.insertOrThrow(table, null, cv);
} catch (SQLException ignore) {
newID = database.replace(table, null, cv);
}
if (newID <= 0) {
Log.e("TAG, "Failed to insert or replace row into " + uri);
} else {
// you are good...increment numInserted
numInserted++;
}
}
db.setTransactionSuccessful();
getContext().getContentResolver().notifyChange(uri, null);
} finally {
db.endTransaction();
}
return numInserted;