I have created a table (Detail) with two columns one column (ID) is primary and auto-increment while the other column (EmpName) is varchar type. While inserting data in database i am only inserting data in EmpName column using the following code. But I want to know the details of that record (ID and name but i know only name and ID is created by database). I can write another select statement and get the last record of the cursor after executing the insert query but if another insertion will be done before executing the select statements then my database will give me wrong result. How can i get the details?
ContentValues initialvalues = new ContentValues();
initialvalues.put("EmpName", "John");
db.insert("Detail", null, initialvalues);// db is database
The above code is working fine for insertion of data in database but How to get that details?
please the API:SQLiteStatement.executeInsert()
According to the source code:
/**
* Execute this SQL statement and return the ID of the row inserted due to this call.
* The SQL statement should be an INSERT for this to be a useful call.
*
* #return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
*
* #throws android.database.SQLException If the SQL string is invalid for
* some reason
*/
public long executeInsert() {
BlockGuard.getThreadPolicy().onWriteToDisk();
if (!mDatabase.isOpen()) {
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
}
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
acquireReference();
try {
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
} finally {
releaseReference();
mDatabase.unlock();
}
}
Related
I am having a table named keywords in database.I want to retrieve data of alarm and location columns from this table and unable to retrieve them except for contact number.For now I am showing their values in a Toast but every time I run any query to show my alarm or location in Toast its empty.But my contact_number is always shown.Don't understand the cause of this problem .I have also checked my tables view and it is showing the values of alarm ,location in them.
Create Table keywords( contact_number text primary key , alarm text , location text )
and my insert function is
public boolean insertkeys (String alarm ,String location ,String contact){
SQLiteDatabase db = this.getWritableDatabase();
//ContentValues is a name value pair, used to insert or update values into database tables.
// ContentValues object will be passed to SQLiteDataBase objects insert() and update() functions.
// ContentValues contentValues = new ContentValues();
ContentValues contentValues = new ContentValues();
contentValues.put("alarm",alarm);
contentValues.put("location",location);
contentValues.put("contact_number",contact);
long ins = db.insert("keywords",null,contentValues);
long upd = db.update("keywords",contentValues,"contact_number = ?",new String[]{contact});
// db.close();
if(ins == -1 && upd == -1)
return false;
else
return true;
}
I am inserting plus updating my data every single time my save button is clicked.Can anyone here tell how can I write a query to retrieve data of these fields and set it to Toast or Edit text. I am new to Database and stuck here for about a week. Thanks in advance for help :)
You extract data via a SELECT query which is returned as a Cursor when using the Android SDK.
The Cursor is similar to a table in that it has a number of rows, each with a set number of columns as determined by what you select.
To get all rows the SELECT query would be along the lines of :-
`SELECT * FROM keywords`
To do this using the Android SDK you could use the SQLiteDatabase query convenience method e.g. for the above you could use :-
Cursor cursor = db.query("keywords",null,null,null,null,null,null);
check the links above for the values/parameters that can be passed and how they correlate with the SELECT statement.
You then traverse the returned cursor extracting the data, typically using the Cursor's move??? methods. Noting that most will return false if the move could not be made and also noting that the original position in the Cursor is before the first row
As such you could have a method that returns a Cursor as per :-
public Cursor getAllKeys(){
SQLiteDatabase db = this.getWritableDatabase();
return db.query("keywords",null,null,null,null,null,null);
}
You could then process all the rows using :-
Cursor csr = yourDBHelper.getAllKeys();
while (csr.moveToNext()) {
String current_contact_number = csr.getString(csr.getColumnIndex("contact_number");
String current_alarm = csr.getString(csr.getColumnIndex("alarm");
String current_location = csr.getString(csr.getColumnIndex("location"));
...... your code to Toast or use the retrieved values
}
csr.close(); //<<<<<<<<<< you should always close a Cursor when finished with it.
Additional
In regard to the comment :-
Cursor query which you have suggested I tried to make changes in it
like putting column and where clause but after that it returns me
nothing when I execute it.Could you tell me that query too.
The following could be a method to retrieve just the alarm according to a contact number.
public String getAlarmByContactNumber(String contactNumber){
String rv = "";
SQLiteDatabase db = this.getWritableDatabase();
Cursor csr = db.query(
"keywords", //<<<<<<<<<<<< the FROM clause (less the FROM keyword) typically the name of the table from which the data is to be extracted (but can include JOINS for example, for more complex queries)
new String[]{"alarm"}, //<<<<<<<<<< A String[] of the column names to be extracted (null equates to * which means all columns) (note can be more complex and include functions/sub queries)
"contact_number=?", //<<<<<<<<<< WHERE clause (less the WHERE keyword) note **?** are place holders for parameters passed as 4th argument
new String[]{contactNumber},
null, //<<<<<<<<<< GROUP BY clause (less the GROUP BY keywords)
null, //<<<<<<<<<< HAVING clause (less the HAVING keyword)
null //<<<<<<<<<< ORDER BY clause (less the ORDER BY keywords)
);
if (csr.moveToFirst()) {
rv = csr.getString(csr.getColumnIndex("alarm"));
}
csr.close();
return rv;
}
The above assumes that you would only have/want one alarm per contact number.
The above is in-principle code, it has not been run or tested and may therefore contain some minor errors.
I am using this method to get query for this string:
public void deletedata(){
p=srt.split(",");
DatabaseHandler dba=new DatabaseHandler(this);
for(String s:p) {
dba.removeSingleproduct(s);
}
Database method is :
public boolean removeSingleproduct(String name) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(tablename, productinserted + "=" + name, null) > 0;
}
I want to delete only one row by calling database as product inserted can have two same value.
Please help guys.
Since you're deleting with a selectedValue String,
add a single quote before and after the name
return db.delete(tablename, productinserted + " = '" + name + "'", null) > 0;
Or you can simplify your code.
public int removeSingleproduct(String name) {
return getWritableDatabase().delete(tablename, productinserted + " = ?", new String[] { name });
}
Return int - the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause.
The following will use the name to locate all rows with the provided name but only delete the first according to it's rowid (unless WITHOUT ROWID has been specified [very likely not]).
public boolean removeSingleproduct(String name) {
boolean rv = false;
SQLiteDatabase db = this.getWritableDatabase();
Cursor csr = db.query(tablename,new String[]{"rowid AS dltid"},productinserted + "=?",new String[]{name},null,null,null);
if(csr.moveToFirst()) {
rv = db.delete(tablename,"rowid=?",new String[]{Long.toString(csr.getLong(csr.getColumnIndex("dltid")))}) > 0;
}
csr.close();
return rv;
}
If you wanted to ensure that a row was only deleted if multiple rows with the same productinserted name existed, then you could simply change
if(csr.moveToFirst()) { ........
to
if(csr.moveToFirst() && csr.getCount() > 1) { .......
Note! csr.moveToLast() could be used instead of csr.moveToFirst() it would probably then delete the newest addition rather than probably deleting the oldest addition.
If you think
but I haven't defined a column called rowid
then :-
Except for WITHOUT ROWID tables, all rows within SQLite tables have a
64-bit signed integer key that uniquely identifies the row within its
table. This integer is usually called the "rowid". The rowid value can
be accessed using one of the special case-independent names "rowid",
"oid", or "rowid" in place of a column name. If a table contains a
user defined column named "rowid", "oid" or "rowid", then that name
always refers the explicitly declared column and cannot be used to
retrieve the integer rowid value.
SQL As Understood By SQLite - ROWIDs and the INTEGER PRIMARY KEY
When I want to check and see if something exists in my ContentProvider what I usually do is something similar to this
Cursor c = getContentResolver().query(table,projection,selection,selectionArgs,sort);
if(c != null && c.moveToFirst()){
//item exists so update
}else{
//item does not exist so insert
}
but that means I always have to make possibly an unnecessary Database call slowing things down especially the greater number of checks on the database I need to do. There has to be a better way to handle this so I dont always have to query first.
I looked at this question
Android Contentprovider - update within an insert method
but using insertWithOnConflict only checks the primary key id and in my case that will not work because what I am checking is not the id but a unique string from a server database.
so is there something I can do with the Content Provider so I dont always have to make a query to check if the item exists in it already?
You can have UNIQUE constraint on columns different than ID one. Example:
CREATE TABLE TEST (_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER NOT NULL, name TEXT, UNIQUE(server_id))
Having this table, in the insert method of your Content Provider you can do something like this:
#Override
public Uri insert(Uri uri, ContentValues contentValues) {
final SQLiteDatabase db = mDatabase.getWritableDatabase();
final int match = mUriMathcer.match(uri);
switch (match) {
case TEST:
insertOrUpdateById(db, uri, "TEST",
contentValues, "server_id");
getContext().getContentResolver().notifyChange(uri, null, false);
return Contract.Test.buildTestUri(contentValues.getAsString("server_id"));
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
/**
* In case of a conflict when inserting the values, another update query is sent.
*
* #param db Database to insert to.
* #param uri Content provider uri.
* #param table Table to insert to.
* #param values The values to insert to.
* #param column Column to identify the object.
* #throws android.database.SQLException
*/
private void insertOrUpdateById(SQLiteDatabase db, Uri uri, String table,
ContentValues values, String column) throws SQLException {
try {
db.insertOrThrow(table, null, values);
} catch (SQLiteConstraintException e) {
int nrRows = update(uri, values, column + "=?",
new String[]{values.getAsString(column)});
if (nrRows == 0)
throw e;
}
}
I hope it helps. Cheers!
Edy Bolos answer can be simply written as
CREATE TABLE TEST (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER NOT NULL,
name TEXT UNIQUE ON CONFLICT REPLACE);
Add UNIQUE ON CONFLICT REPLACE in create table query.
Use REPLACE INTO instead of INSERT INTO to solve the issue
I would like to create a FIFO table in order to save only the most 50 recent infomations by deleting the oldest elements when a new infomation arrives. I can do it by manipulating ID in the table but I don't think it is the best solution. Any idea of doing it well?
Instead of checking for date time, sorting your items, and whatnot, you can just assume that the first row in your table is the last to be inserted.
In your Content Provider's insert(Uri uri, ContentValues cv), before doing your db.insert call, you can first query the number of items on that table using getCount() and delete the first row if count>50. Then proceed with your insert call.
You dont need to play with IDs in order to create a FIFO logic. The best would be to add another column as DATETIME in your table which automatically inserts current time-stamp that will help you to select records in ascending order with respect to this column. Your new column should be something like:
DateAdded DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
Make sure when ever you insert new record, you must do a COUNT check of total records in this table and if necessary delete the oldest record with respect to DateAdded. Moreover, you can make use of LIMIT and/or MAX in your select-query when it comes to delete the oldest record.
Add a datetime type column to your table if it doesn't contain it yet and set it to 'now' on each insert. Then on each insert select all with limit set to 50 sorted by date. Choose the last item and run a delete query to delete everything older than this last item.
is it must to use sqlite? can you use file handling? you can use simple Queue object and save it to file.
Here is what I did for a list of transactions, and it works okay. When inserting a new entry I check if the count is above 50, if so, I just delete the very last entry:
// Adding new transaction
public void addTransaction(Transaction transaction) {
SQLiteDatabase db = this.getWritableDatabase();
if(getTransactionsCount() > 50){
List<Transaction> allTransactions = getAllTransactions();
Transaction oldestTransaction = allTransactions.get(allTransactions.size()-1);
deleteTransaction(oldestTransaction);
}
ContentValues values = new ContentValues();
values.put(KEY_TRANSACTION_UID, transaction.getUID());
values.put(KEY_TRANSACTION_AMOUNT, transaction.getAmount());
values.put(KEY_TRANSACTION_IS_ADD, transaction.getIsAdd());
// Inserting Row
db.insert(TABLE_TRANSACTIONS, null, values);
db.close(); // Closing database connection
}
And getAllTransactions() returns the list in descending order (based on the id primary key):
// Getting All Transactions
public List<Transaction> getAllTransactions() {
List<Transaction> transactionList = new ArrayList<Transaction>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_TRANSACTIONS + " ORDER BY " + KEY_TRANSACTION_ID + " DESC";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Transaction transaction = new Transaction();
transaction.setID(Integer.parseInt(cursor.getString(0)));
transaction.setUID(cursor.getString(1));
transaction.setAmount(cursor.getString(2));
transaction.setIsAdd(cursor.getString(3));
// Adding contact to list
transactionList.add(transaction);
} while (cursor.moveToNext());
}
// return contact list
return transactionList;
}
I'm creating an activity that views a record and displays it's data to a user to modify. After everything is done just click a button to save the data back into the database. However, once saving time comes around I get an unusual "java.lang.IllegalArgumentException: Empty values" error. I think it's a SQL code error on my end, but I don't know enough about SQL to find it. Can I get a couple of eyes to see what I did wrong?
Thanks
~Aedon
Here is where the save button is declared and the listener is set. mBoundService is the service that hosts the database and it's calls. DevicesTable is a class that holds the table and column names. DevicesTable.gt_fields[0] is autoincrementID and then serial, name, and first seen columns
public void init() {
mDevName = (EditText)findViewById(R.id.dv_name);
mCurReads = (TextView)findViewById(R.id.dv_readings);
mSave = (Button)findViewById(R.id.dv_save);
mSave.setOnClickListener(new OnClickListener() {
#Override public void onClick(View arg0) {
mBoundService.updateRecord(DevicesTable.gt_name, mId, DevicesTable.g_fields[2], mDevName.getText().toString());
}
});
}
And this is the database call itself.
/**
* Updates a record at the given table with the given record.
* #param table The table to update
* #param id The id of the actual record. Do not pass the incorrect id!
* #param column The column in which the data is changing
* #param data The data that is to be changed to
*/
public void updateRecord(String table, String id, String column, String data) {
mDB.update(table, null, "SET " + column + " = '" + data + "',", new String[]{"id=" + id});
}
You need to pass in a ContentValues object to tell the database what values go in what columns in the updated row(s). The strings in the third and fourth arguments make up a WHERE clause that indicate what row(s) should be updated. For example:
ContentValues values = new ContentValues();
values.put("foo", 123);
values.put("bar", 456);
db.update("some_table", values, "id=789", null);
This would be equivalent to issuing the query
UPDATE some_table SET foo = 123, bar = 456 WHERE id = 789
Your code attempts to stuff the entire query into the WHERE clause, and update() stops you in your tracks because the values argument is null.