Get a SQLite row based on title and date - android

I want to get a single row based on title and date.
I have created some code, but i it correct? What are all the null-fields in the code?
public Cursor getRecordFromMondayByTitleDate(String inpRowTitle, String inpRowDate) throws SQLException
{
Cursor mCursor =
db.query(DATABASE_TABLE_MONDAY, new String[] {KEY_M_ROWID, KEY_M_TITLE, KEY_M_DATE,
KEY_M_WEIGHT, KEY_M_SET_A, KEY_M_SET_B,
KEY_M_SET_C, KEY_M_SET_D},
KEY_M_TITLE + "= '" + inpRowTitle + "'",
null,
KEY_M_DATE + "= '" + inpRowDate + "'",
null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
My database table DATABASE_TABLE_MONDAY layout is the following:
private static final String DATABASE_CREATE_TABLE_MONDAY =
"create table if not exists " + DATABASE_TABLE_MONDAY + " (m_id integer primary key autoincrement, "
+ "m_title VARCHAR not null, m_date date, m_weight DOUBLE, m_set_a INT, m_set_b INT, m_set_c INT, m_set_d INT);";
Thanks for the help!

I believe your query should look more like this:
db.query(DATABASE_TABLE_MONDAY,
new String[] {KEY_M_ROWID, KEY_M_TITLE, KEY_M_DATE, KEY_M_WEIGHT, KEY_M_SET_A, KEY_M_SET_B, KEY_M_SET_C, KEY_M_SET_D},
KEY_M_TITLE + "='" + inpRowTitle + "' AND " + KEY_M_DATE + "='" + inpRowDate + "'",
null,
null,
null,
null);
Your table and columns parameters were correct. The third parameter, the selection parameter, is essentially the WHERE clause from SQL, so you want both your title and date specified here. The fourth parameter is selectionArgs, and is there to "help" with coding the selection. If you specify a selection with question marks, the question marks are replaced, in order, with the values in the array you provide. Using selectionArgs is not necessary, and you can pass null if your selection is written in full. After that, the parameters specify how you want the query returned to you, and all may be passed a null value. The fifth is groupBy, and corresponds to the SQL clause GROUP BY. The sixth corresponds to HAVING, the seventh to ORDER BY. The last parameter is limit, and just puts a cap on how many records a query returns. If you don't need to limit your query, you can just omit this parameter, as there is a query() method without limit. If you're unfamiliar with SQL, you may want to do a little studying to know what each of those clauses does for your query.

Related

SQLite getting the row with the max value

So I have a filled in Database with the columns: _ID, excersise, reps and timestamp. Im trying to print out the row with the highest rep number of an excersise with this Cursor:
private Cursor getRepRecord(String excersise) {
return myDatabase.query(Contact.ExcersiseEntry.TABLE_NAME,
new String [] {"MAX(reps)"},
Contact.ExcersiseEntry.EXCERSISE_NAME + "= '" + excersise + "'",
null,
null,
null,
Contact.ExcersiseEntry.EXCERSISE_REPS + " DESC");
}
and then I use this method to print the cursor rows:
private void getEntryFromDatabase(Cursor cursor) {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String excersise = cursor.getString(cursor.getColumnIndex(Contact.ExcersiseEntry.EXCERSISE_NAME));
int reps = cursor.getInt(cursor.getColumnIndex(Contact.ExcersiseEntry.EXCERSISE_REPS));
int id = cursor.getInt(cursor.getColumnIndex(Contact.ExcersiseEntry._ID));
Log.i("Entry", "ID: " +id + " || Excersise: " + excersise + " || reps: " + Integer.toString(reps));
cursor.moveToNext();
}
}
How ever I get the Error: CursorWindow: Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 1 columns. I know there are alot of similar questions but I looked at man and still couldn´t find the Solution...
The reason why you are getting the -1 is because the columns you are trying to extract data from do not exist in the Cursor (the getColumnIndex method returns -1 if the column cannot be found).
The Cursor will only have a single column named MAX(reps).
You can easily add all the other columns by adding * (separated from the MAX(reps) column by a comma or you could add other columns individually as elements of the array. If you want to display the maximum reps you would extract the column named MAX(reps) or you could rename the column using AS e.g. MAX(reps) as maxreps
So you could have :-
private Cursor getRepRecord(String excersise) {
return myDatabase.query(Contact.ExcersiseEntry.TABLE_NAME,
new String [] {"MAX(reps) AS maxreps", *}, //<<<< Changed
Contact.ExcersiseEntry.EXCERSISE_NAME + " = '" + excersise + "'",
null,
null,
null,
Contact.ExcersiseEntry.EXCERSISE_REPS + " DESC");
}
This could be used in conjunction with a slightly amended getEntryFromDatabase method :-
private void getEntryFromDatabase(Cursor cursor) {
//cursor.moveToFirst(); //<<< does nothing of any use as return value is ignored
while (!cursor.isAfterLast()) {
String excersise = cursor.getString(cursor.getColumnIndex(Contact.ExcersiseEntry.EXCERSISE_NAME));
int reps = cursor.getInt(cursor.getColumnIndex(Contact.ExcersiseEntry.EXCERSISE_REPS)); // Would this be of any use???
int id = cursor.getInt(cursor.getColumnIndex(Contact.ExcersiseEntry._ID));
int maxreps = cursor.getInt(cursor.getColumnIndex("maxreps")); //<<<< Added
Log.i("Entry", "ID: " +id + " || Excersise: " + excersise + " || reps: " + Integer.toString(reps) + " || maxreps: " + Integer.toString(maxreps);
cursor.moveToNext();
}
}
EDIT re comment :-
I still don´t quite understand why. The correct SQL term would be
something like SELECT * WHERE reps = max(reps), right? How does it
translate into the Max(reps), *
If you used SELECT * FROM reps WHERE reps = Max(reps) it would return all defined columns (the * translates to all columns) for the row or rows that is/are equal to highest rep value (note see below why this would work anyway). Which could be what you want. (ORDER BY reps DESC (or ASC) is irrelevant).
The list of columns after SELECT (SELECT ALL or SELECT DISTINCT) defined the result_columns i.e. the columns that will exist in the resultant Cursor. If you said SELECT reps FROM reps then the resultant cursor would have just the 1 column called reps. SELECT reps, exercise then the resultant cursor would have two columns.
SQL allows derived columns (my term). The derived column name will take the name of the expression used to derive the value. So if you say SELECT max(reps) FROM reps then the result will be a Cursor with 1 column named max(reps) (and because MAX is an aggregate function 1 row (unless GROUP BY is used)).
The query method used (there are 4 in total) in your code has the signature :-
Cursor query (String table,
String[] columns, //<<<< list of result columns
String selection, //<<<< WHERE CLAUSE
String[] selectionArgs,
String groupBy,
String having,
String orderBy)
So :-
myDatabase.query(Contact.ExcersiseEntry.TABLE_NAME,
new String [] {"MAX(reps)"},
Contact.ExcersiseEntry.EXCERSISE_NAME + "= '" + excersise + "'",
null,
null,
null,
Contact.ExcersiseEntry.EXCERSISE_REPS + " DESC");
results in the SQL SELECT MAX(reps) FROM reps WHERE excercise = 'your_excercise';
So the resultant Cursor will have 1 column named MAX(reps).
If you wanted SELECT * FROM reps WHERE reps = MAX(reps) then you'd use :-
myDatabase.query(Contact.ExcersiseEntry.TABLE_NAME,
null, //<<<< ALL columns
Contact.ExcersiseEntry.EXCERSISE_REPS + " = MAX(reps)",
null,
null,
null,
Contact.ExcersiseEntry.EXCERSISE_REPS + " DESC" // Irrelevant
);
However, this would be for all Exercises and could thus return multiple rows BUT it would be a misuse of an aggregate function (attempt apply the function on a per row basis as opposed to on a per group basis (all rows are the group as no GROUP BY has been specified)).
You'd have to use a subquery e.g. SELECT * FROM reps WHERE reps = (SELECT MAX(reps) FROM reps)

how to check if a value already exist in db, and if so how to get the id of that row? android sql

i have created the next db file -
String sql = ""
+ "CREATE TABLE "+ Constants.TABLE_NAME + " ("
+ Constants.NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ Constants.NAME_PERSON + " TEXT"
+ ")";
db.execSQL(sql);
Now what I would like to know is, how to be able to run on the db and to know if a name already exist sin the db, and if so i would like to get the id of that row.
all i can understand is that i should use the
Cursor c= db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy)
but I don't have a clue what I should do next -
so thanks for any kind of help
you can add this in your DB and call the function passing "to be searched key" as an argument
public boolean checkIfExist(String name) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_INFO, new String[] { KEY_TITLE}, KEY_TITLE + "=?",
new String[] { name }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
if (cursor.moveToFirst()) {
return true;
}else{
return false;
}
}
Where KEY_TITLE is the column name in your table.
Take more example on this:
AndroidSQLite
AndroidSQLite with multi tables
Make a SELECT request. Then check with if(cursor.moveToFirst()) if your name is already existing. (moveToFirst() return true if there is at least 1 value).
So if your value is existing, juste get its id with cursor.getString(cursor.getColumnIndex("_id"));

Querying sqlite in android

I'm creating a database for my game, everything is working until I want to query one item.
I have been trying few different methods and I can't make it work. I just simply don't see the error in my code.
The code is as follows:
public Item getItem(String icon) {
String[] columns = {KEY_ID, KEY_TYPE, KEY_ICON, KEY_LEVEL, KEY_ARMOR, KEY_DAMAGE, KEY_BUY, KEY_SELL};
Cursor cursor = db.query(DB_TABLE, columns, KEY_ICON + "=" + icon,
null, null, null, null);
Item item=null;
if(cursor != null && cursor.moveToFirst()) {
item= new Item(cursor.getString(TYPE_COLUMN),
cursor.getString(ICON_COLUMN),
cursor.getString(LEVEL_COLUMN),
cursor.getString(ARMOR_COLUMN),
cursor.getString(DAMAGE_COLUMN),
cursor.getString(BUY_COLUMN),
cursor.getString(SELL_COLUMN)
);
}
return item;
}
The error I'm getting is
No such column: fast_boots (code 1): while compiling: SELECT id, type,
icon, level, armor, damage, buy, sell from items where icon=fast_boots
When trying to find .getItem("fast_boots"); I do see the fast_boots in my sql database
To make the query work, maybe you should try this :
KEY_ICON + "= '" + icon + "' "
As 'icon' is a string value. Since you're not specifying it, it is probably trying to understand it as being a column in the projection
This is the wrong way of implementing such functionality, though. Do not perform database queries on the getItem() method itself (main thread), it deserves to run in background, so it won't affect the main thread.
Please read about AsyncTask.
Try this
Cursor cursor = db.query(DB_TABLE, columns, KEY_ICON + "='" + icon +"'",
null, null, null, null);
I added '

SQLite Query in Android to count rows

I'm trying to create a simple Login form, where I compare the login id and password entered at the login screen with that stored in the database.
I'm using the following query:
final String DATABASE_COMPARE =
"select count(*) from users where uname=" + loginname + "and pwd=" + loginpass + ");" ;
The issue is, I don't know, how can I execute the above query and store the count returned.
Here's how the database table looks like ( I've manged to create the database successfully using the execSQl method)
private static final String
DATABASE_CREATE =
"create table users (_id integer autoincrement, "
+ "name text not null, uname primary key text not null, "
+ "pwd text not null);";//+"phoneno text not null);";
Can someone kindly guide me as to how I can achieve this? If possible please provide a sample snippet to do the above task.
DatabaseUtils.queryNumEntries (since api:11) is useful alternative that negates the need for raw SQL(yay!).
SQLiteDatabase db = getReadableDatabase();
DatabaseUtils.queryNumEntries(db, "users",
"uname=? AND pwd=?", new String[] {loginname,loginpass});
#scottyab the parametrized DatabaseUtils.queryNumEntries(db, table, whereparams) exists at API 11 +, the one without the whereparams exists since API 1. The answer would have to be creating a Cursor with a db.rawQuery:
Cursor mCount= db.rawQuery("select count(*) from users where uname='" + loginname + "' and pwd='" + loginpass +"'", null);
mCount.moveToFirst();
int count= mCount.getInt(0);
mCount.close();
I also like #Dre's answer, with the parameterized query.
Use an SQLiteStatement.
e.g.
SQLiteStatement s = mDb.compileStatement( "select count(*) from users where uname='" + loginname + "' and pwd='" + loginpass + "'; " );
long count = s.simpleQueryForLong();
See rawQuery(String, String[]) and the documentation for Cursor
Your DADABASE_COMPARE SQL statement is currently invalid, loginname and loginpass won't be escaped, there is no space between loginname and the and, and you end the statement with ); instead of ; -- If you were logging in as bob with the password of password, that statement would end up as
select count(*) from users where uname=boband pwd=password);
Also, you should probably use the selectionArgs feature, instead of concatenating loginname and loginpass.
To use selectionArgs you would do something like
final String SQL_STATEMENT = "SELECT COUNT(*) FROM users WHERE uname=? AND pwd=?";
private void someMethod() {
Cursor c = db.rawQuery(SQL_STATEMENT, new String[] { loginname, loginpass });
...
}
Assuming you already have a Database (db) connection established, I think the most elegant way is to stick to the Cursor class, and do something like:
String selection = "uname = ? AND pwd = ?";
String[] selectionArgs = {loginname, loginpass};
String tableName = "YourTable";
Cursor c = db.query(tableName, null, selection, selectionArgs, null, null, null);
int result = c.getCount();
c.close();
return result;
how to get count column
final String DATABASE_COMPARE = "select count(*) from users where uname="+loginname+ "and pwd="+loginpass;
int sometotal = (int) DatabaseUtils.longForQuery(db, DATABASE_COMPARE, null);
This is the most concise and precise alternative. No need to handle cursors and their closing.
If you are using ContentProvider then you can use:
Cursor cursor = getContentResolver().query(CONTENT_URI, new String[] {"count(*)"},
uname=" + loginname + " and pwd=" + loginpass, null, null);
cursor.moveToFirst();
int count = cursor.getInt(0);
If you want to get the count of records then you have to apply the group by on some field or apply the below query.
Like
db.rawQuery("select count(field) as count_record from tablename where field =" + condition, null);
Another way would be using:
myCursor.getCount();
on a Cursor like:
Cursor myCursor = db.query(table_Name, new String[] { row_Username },
row_Username + " =? AND " + row_Password + " =?",
new String[] { entered_Password, entered_Password },
null, null, null);
If you can think of getting away from the raw query.
int nombr = 0;
Cursor cursor = sqlDatabase.rawQuery("SELECT column FROM table WHERE column = Value", null);
nombr = cursor.getCount();

How do I join two SQLite tables in my Android application?

Background
I have an Android project that has a database with two tables: tbl_question and tbl_alternative.
To populate the views with questions and alternatives I am using cursors. There are no problems in getting the data I need until I try to join the two tables.
Tbl_question
-------------
_id
question
categoryid
Tbl_alternative
---------------
_id
questionid
categoryid
alternative
I want something like the following:
SELECT tbl_question.question, tbl_alternative.alternative where
categoryid=tbl_alternative.categoryid AND tbl_question._id =
tbl_alternative.questionid.`
This is my attempt:
public Cursor getAlternative(long categoryid) {
String[] columns = new String[] { KEY_Q_ID, KEY_IMAGE, KEY_QUESTION, KEY_ALT, KEY_QID};
String whereClause = KEY_CATEGORYID + "=" + categoryid +" AND "+ KEY_Q_ID +"="+ KEY_QID;
Cursor cursor = mDb.query(true, DBTABLE_QUESTION + " INNER JOIN "+ DBTABLE_ALTERNATIVE, columns, whereClause, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
I find this way to form queries harder than regular SQL, but have gotten the advice to use this way since it is less error prone.
Question
How do I join two SQLite tables in my application?
You need rawQuery method.
Example:
private final String MY_QUERY = "SELECT * FROM table_a a INNER JOIN table_b b ON a.id=b.other_id WHERE b.property_id=?";
db.rawQuery(MY_QUERY, new String[]{String.valueOf(propertyId)});
Use ? bindings instead of putting values into raw sql query.
An alternate way is to construct a view which is then queried just like a table.
In many database managers using a view can result in better performance.
CREATE VIEW xyz SELECT q.question, a.alternative
FROM tbl_question AS q, tbl_alternative AS a
WHERE q.categoryid = a.categoryid
AND q._id = a.questionid;
This is from memory so there may be some syntactic issues.
http://www.sqlite.org/lang_createview.html
I mention this approach because then you can use SQLiteQueryBuilder with the view as you implied that it was preferred.
In addition to #pawelzieba's answer, which definitely is correct, to join two tables, while you can use an INNER JOIN like this
SELECT * FROM expense INNER JOIN refuel
ON exp_id = expense_id
WHERE refuel_id = 1
via raw query like this -
String rawQuery = "SELECT * FROM " + RefuelTable.TABLE_NAME + " INNER JOIN " + ExpenseTable.TABLE_NAME
+ " ON " + RefuelTable.EXP_ID + " = " + ExpenseTable.ID
+ " WHERE " + RefuelTable.ID + " = " + id;
Cursor c = db.rawQuery(
rawQuery,
null
);
because of SQLite's backward compatible support of the primitive way of querying, we turn that command into this -
SELECT *
FROM expense, refuel
WHERE exp_id = expense_id AND refuel_id = 1
and hence be able to take advanatage of the SQLiteDatabase.query() helper method
Cursor c = db.query(
RefuelTable.TABLE_NAME + " , " + ExpenseTable.TABLE_NAME,
Utils.concat(RefuelTable.PROJECTION, ExpenseTable.PROJECTION),
RefuelTable.EXP_ID + " = " + ExpenseTable.ID + " AND " + RefuelTable.ID + " = " + id,
null,
null,
null,
null
);
For a detailed blog post check this
http://blog.championswimmer.in/2015/12/doing-a-table-join-in-android-without-using-rawquery
"Ambiguous column" usually means that the same column name appears in at least two tables; the database engine can't tell which one you want. Use full table names or table aliases to remove the ambiguity.
Here's an example I happened to have in my editor. It's from someone else's problem, but should make sense anyway.
select P.*
from product_has_image P
inner join highest_priority_images H
on (H.id_product = P.id_product and H.priority = p.priority)

Categories

Resources