Query in ContentValues - android

I have to insert a lot of rows in my SQLite Database and for some tables
a specific value of each row has to be converted into an other using the value of an other table.
Actually, I have this function which is working well:
public void myFunction( String tableName, String attrName, ContentValues currentVal ) {
SQLiteDatabase database = this.getReadableDatabase();
Cursor c = database.rawQuery("SELECT colName FROM "+tableName+" WHERE "+tableName+".otherColName = " + currentVal.getAsString(attrName), null);
Long realValue = null;
if( c.moveToFirst() ) {
realValue = c.getLong(0);
}
if( c != null ) c.close();
currentVal.put( attrName, realValue );
}
But, this is really time consumimg because of this part:
if( c.moveToFirst() ) {
realValue = c.getLong(0);
}
So I wanted to know if there's a way to set the query directly in the value of the ContantValue like this:
currentVal.put( attrName, "SELECT colName FROM "+tableName+" WHERE "+tableName+".otherColName = " + currentVal.getAsString(attrName));
and the query will be executed at the same time as the insert query in order to replace the value.
Thank you beforehand!

No, ContentValues is just a wrapper of a hash map for the data. You can try to use index to accelerate the query.

Related

Sqlite how to improve performance?

I have to make more than 300 selects from my database.
Each of those queries has to be called inside of a for each loop, here's an example:
for(int id : myids){
Cursor cursor = MyDatabaseHelper.runMyQuery(id);
while(cursor.moveToNext()){
//my stuff...
}
}
MyDatabaseHelper is an instance of a database helper class, the function is like this
public Cursor runMyQuery(int id){
SQLiteDatabase db = this.getWritableDatabase();
Cursor ret = db.rawQuery("select Name, Surname, Age from PTable where Id = " + id, null);
return ret;
}
I've been told that the constant "open and close" of the db because of multiple queries it the cause of my performance issues and I should, instead, make a single query (using union etc).
Changing my code to a single query would mean changing the entire database, and I was hoping not to do that.
Is there anything I can do to improve the performance and keep the multiple selects at the same time?
Thanks
I think what you are looking for is the in clause.
Convert your myids into a string. Something like
String inClause = "(1,2,3)"
and you can use it as
"select Name, Surname, Age from PTable where Id in " + inClause
You can read more of the in operator here
You can return a single Cursor containing all the rows.
First change your runMyQuery() method to this:
public Cursor runAll(String list){
SQLiteDatabase db = this.getWritableDatabase();
String sql = "select Name, Surname, Age from PTable where " + list + " like '%,' || id || ',%'"
Cursor ret = db.rawQuery(sql, null);
return ret;
}
So you pass to the method runAll() a String which is the the comma separated list of all the ids that you have in myids and with th eoperator LIKE you compare it to each id of the table.
You create this list and get the results in a Cursor object like this:
StringBuilder sb = new StringBuilder(",");
for(int id : myids){
sb.append(String.valueOf(id)).append(",");
}
String list = sb.length() > 1 ? sb.toString() : "";
if (list.length() > 0) {
Cursor c = runAll(list);
while(c.moveToNext()){
//your stuff...
}
}

Android SqlLite check if two values exist in 2 different columns

I am developing an application where the user inputs title and the date. I want to prevent the duplicated titles being inputted on the same day in to database. I am checking if the title exists on the selected date. However my query seems not to work and i don't know why, the application just crashes.Is this query correct? Can someone help?
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.moveToFirst();
c.close();
return exists;
}
One issue that you have is that c.moveToFirst will always fail if a match does not exist as you are trying to move to a row in an empty cursor.
The resolution is to not use c.moveToFirst and instead get the count of the rows and then set the return value accordingly.
e.g.
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.getCount() > 0;
c.close();
return exists;
}
The second issue is that the query itself is wrong as you do not have spaces either side of the AND keyword. That is instead of
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
You should have
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +" AND " + DATE+"=?", new String[] {title,date});
Personally, I setup constants for SQL keywords that include the space and then use these. So I'd have something along the lines of +TITLE+"=?" + SQLAND + DATE+"=?". Where SQLAND would be defined along the lines of String SQLAND=" AND ";
PS look at Cricket_007's answer, the code is neater/better it's easier to read.
Your spacing is off. TITLE+"=?" +"AND" + DATE becomes TITLE=?ANDDATE=?
I would suggest this. See DatabaseUtils.queryNumEntries
public boolean checkExist(String title, String date) {
SQLiteDatabase db = getReadableDatabase();
String[] args = new String[] {title,date};
String filter = String.format("%s=? AND %s=?", TITLE, DATE);
return DatabaseUtils.queryNumEntries(db, TABLE_NAME, filter, args) > 0;
}
you should be using c.getCount() instead of c.moveToFirst()
if the value is greater than 0, then it exists

Android/SQLite. Insert multiple values in database with filtration?

I try to insert into a database some values(message body and date) only if the phone number (number) doesn't exist in it, but my code doesn't working. Can you give some advice?
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+") SELECT "+number+" WHERE NOT EXISTS "
+ "(SELECT 1 FROM version2 WHERE number = "+number+")", null);
if (cursor.moveToFirst()) {
do {
} while (cursor.moveToNext());
}
}
Try this query.
Seems like your select query is incorrect while insert record.
INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+") WHERE number IS NOT NULL or number <> '';
You need to create a method which will check for the duplicate phone number.
private boolean isPhoneExists ( long number )
{
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select phone from version2 where number = " + number, null );
if (cursor.getCount() > 0)
return true;
else
return false;
}
//Now your inserting statement
if ( !isPhoneExists ( "987654321" ) )
{
Cursor cursor = db.rawQuery("INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+")
....
}

Sqlite verify if value of column exists

i'm wondering if this method is right to verify if the value of _username already exists in the column "username"
public boolean verification(String _username) throws SQLException{
Cursor c = dataBase.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+KEY_USERNAME+"="+_username, null);
if (c!=null)
return true; // return true if the value of _username already exists
return false; // Return false if _username doesn't match with any value of the columns "Username"
}
Is there a better way to do the same thing, i'm really not sure about this, it seemed right for me.
Thanks.
Beware of SQL injection attacks! You should always use a parameterized query:
Cursor c = dataBase.rawQuery("SELECT 1 FROM "+TABLE_NAME+" WHERE "+KEY_USERNAME+"=?", new String[] {_username});
(Honestly I'm not sure how your first query didn't throw an exception since you forgot to wrap the string in quotes...)
Also rawQuery() will always return a Cursor, you must check if the Cursor is empty, not null.
As for "the best" approach, this works fine, but I recommend closing the Cursor to free up resources. All together:
public boolean verification(String _username) {
Cursor c = dataBase.rawQuery("SELECT 1 FROM "+TABLE_NAME+" WHERE "+KEY_USERNAME+"=?", new String[] {_username});
boolean exists = c.moveToFirst();
c.close();
return exists;
}
Is there a better way to do the same thing, i'm really not sure about
this, it seemed right for me. Thanks.
In the terms of security and purity yes, for sure.
public boolean verification(String _username) throws SQLException {
int count = -1;
Cursor c = null;
try {
String query = "SELECT COUNT(*) FROM "
+ TABLE_NAME + " WHERE " + KEY_USERNAME + " = ?"
c = dataBase.rawQuery(query, new String[] {_username});
if (c.moveToFirst()) {
count = c.getInt(0);
}
return count > 0;
}
finally {
if (c != null) {
c.close();
}
}
}
I recommend you to an usage of ? that is called placeholder. Each placeholder will be replaced with value from string array in the same order. This is called also parametrized statement as a defence agains SQL injection. When your work with Cursor is finished, release it.

Get last inserted value from sqlite database Android

I am trying to get the last inserted rowid from a sqlite database in Android. I have read a lot of posts about it, but can't get one to work.
This is my method:
public Cursor getLastId() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_WID}, KEY_WID + "=" + MAX(_id), null, null, null, null, null);}
I have tried with MAX, but I must be using it wrong. Is there another way?
Well actually the SQLiteDatabase class has its own insert method which returns the id of the newly created row. I think this is the best way to get the new ID.
You can check its documentation here.
I hope this helps.
Use
SELECT last_insert_rowid();
to get the last inserted rowid.
If you are using AUTOINCREMENT keyword then
SELECT * from SQLITE_SEQUENCE;
will tell you the values for every table.
To get the last row from the table..
Cursor cursor = theDatabase.query(DATABASE_TABLE, columns,null, null, null, null, null);
cursor.moveToLast();
Use moveToLast() in Cursor interface.
From android.googlesource.com
/**
* Move the cursor to the last row.
*
* <p>This method will return false if the cursor is empty.
*
* #return whether the move succeeded.
*/
boolean moveToLast();
Simple example:
final static String TABLE_NAME = "table_name";
String name;
int id;
//....
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
if(cursor.moveToLast()){
//name = cursor.getString(column_index);//to get other values
id = cursor.getInt(0);//to get id, 0 is the column index
}
Or you can get the last row when insertion(Which is #GorgiRankovski have mentioned):
long row = 0;//to get last row
//.....
SQLiteDatabase db= this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_NAME, name);
row = db.insert(TABLE_NAME, null, contentValues);
//insert() returns the row ID of the newly inserted row, or -1 if an error occurred
Also their is a multiple ways you can do this using query:
One is expressed by #DiegoTorresMilano
SELECT MAX(id) FROM table_name. or to get all columns values SELECT * FROM table_name WHERE id = (SELECT MAX(id) FROM table_name).
If your PRiMARY KEY have sat to AUTOINCREMENT, you can SELECT vaules occording to max to min and limit the rows to 1 using SELECT id FROM table ORDER BY column DESC LIMIT 1
(If you want each and every value, use * instead of id)
If you want the last_insert_id just afert a insert you can use that :
public long insert(String table, String[] fields, String[] vals )
{
String nullColumnHack = null;
ContentValues values = new ContentValues();
for (int i = 0; i < fields.length; i++)
{
values.put(fields[i], vals[i]);
}
return myDataBase.insert(table, nullColumnHack, values);
}
The insert method returns the id of row just inserted or -1 if there was an error during insertion.
long id = db.insert("your insertion statement");
db is an instance of your SQLiteDatabase.
Try this:
public Cursor getLastId() {
return mDb.query(DATABASE_TABLE, new String[] { **MAX(id)** }, null, null, null, null, null, null);}
/**
* #return
*/
public long getLastInsertId() {
long index = 0;
SQLiteDatabase sdb = getReadableDatabase();
Cursor cursor = sdb.query(
"sqlite_sequence",
new String[]{"seq"},
"name = ?",
new String[]{TABLENAME},
null,
null,
null,
null
);
if (cursor.moveToFirst()) {
index = cursor.getLong(cursor.getColumnIndex("seq"));
}
cursor.close();
return index;
}
I use this
public int lastId(){
SQLiteDatabase db =
this.getReadableDatabase();
Cursor res = db.rawQuery( "select * from resep", null );
res.moveToLast();
return res.getInt(0);
}
In your DbHelper class,
public long getLastIdFromMyTable()
{
SQLiteDatabase db = this.getReadableDatabase();
SQLiteStatement st = db.compileStatement("SELECT last_insert_rowid() from " + MY_TABLE);
return st.simpleQueryForLong();
}

Categories

Resources