I am developing a restaurant menu app in Android. My app has one database table which has the following columns:
id (primary key)
category
item name
The category column shows the category of item such as veg, non veg, snacks etc. It has duplicate values and I want to select only distinct values from this column. I have tried the following but it is not working if anyone can provide a solution:
String query = "SELECT DISTINCT category FROM todo";
Cursor cursor = database.rawQuery(query,null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
You can also use this specific query-Method of the SQLiteDatabase class that takes a boolean value to determine whether you want distinct values or not:
public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
Link to Android Reference
This way you don't have to use rawQuery at all.
Try:
"SELECT DISTINCT category as _id, category FROM todo"
This worked for me in the same situation.
This is how i make distinct, also to get categories
// Get Categories
public Cursor getCategories() {
Cursor c = db.rawQuery("SELECT DISTINCT " + KEY_ITEM_CAT + " as " + KEY_ITEM_ID
+ ", " + KEY_ITEM_CAT + " FROM " + ITEMS_TABLE_NAME, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
I was searching for the same question, and I found something which is direct to the solution in the most simplest way! Check out this answer:
https://stackoverflow.com/a/13879436/4072073
Related
I am using the query method of SQLiteDatabase. How do I use the query method?
I tried this:
Cursor cursor = sqLiteDatabase.query(
tableName, tableColumns, whereClause, whereArgs, groupBy, having, orderBy);
tableColumns - columns parameter is constructed as follows.
String[] columns = new String[]{KEY_ID, KEY_CONTENT};
If we need to get all the fields, how should the column parameter to be constructed. Do we need to include all the Field Names in String array?
How do I properly use the query method?
tableColumns
null for all columns as in SELECT * FROM ...
new String[] { "column1", "column2", ... } for specific columns as in SELECT column1, column2 FROM ... - you can also put complex expressions here:
new String[] { "(SELECT max(column1) FROM table1) AS max" } would give you a column named max holding the max value of column1
whereClause
the part you put after WHERE without that keyword, e.g. "column1 > 5"
should include ? for things that are dynamic, e.g. "column1=?" -> see whereArgs
whereArgs
specify the content that fills each ? in whereClause in the order they appear
the others
just like whereClause the statement after the keyword or null if you don't use it.
Example
String[] tableColumns = new String[] {
"column1",
"(SELECT max(column1) FROM table2) AS max"
};
String whereClause = "column1 = ? OR column1 = ?";
String[] whereArgs = new String[] {
"value1",
"value2"
};
String orderBy = "column1";
Cursor c = sqLiteDatabase.query("table1", tableColumns, whereClause, whereArgs,
null, null, orderBy);
// since we have a named column we can do
int idx = c.getColumnIndex("max");
is equivalent to the following raw query
String queryString =
"SELECT column1, (SELECT max(column1) FROM table1) AS max FROM table1 " +
"WHERE column1 = ? OR column1 = ? ORDER BY column1";
sqLiteDatabase.rawQuery(queryString, whereArgs);
By using the Where/Bind -Args version you get automatically escaped values and you don't have to worry if input-data contains '.
Unsafe: String whereClause = "column1='" + value + "'";
Safe: String whereClause = "column1=?";
because if value contains a ' your statement either breaks and you get exceptions or does unintended things, for example value = "XYZ'; DROP TABLE table1;--" might even drop your table since the statement would become two statements and a comment:
SELECT * FROM table1 where column1='XYZ'; DROP TABLE table1;--'
using the args version XYZ'; DROP TABLE table1;-- would be escaped to 'XYZ''; DROP TABLE table1;--' and would only be treated as a value. Even if the ' is not intended to do bad things it is still quite common that people have it in their names or use it in texts, filenames, passwords etc. So always use the args version. (It is okay to build int and other primitives directly into whereClause though)
This is a more general answer meant to be a quick reference for future viewers.
Example
SQLiteDatabase db = helper.getReadableDatabase();
String table = "table2";
String[] columns = {"column1", "column3"};
String selection = "column3 =?";
String[] selectionArgs = {"apple"};
String groupBy = null;
String having = null;
String orderBy = "column3 DESC";
String limit = "10";
Cursor cursor = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
Explanation from the documentation
table String: The table name to compile the query against.
columns String: A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data
from storage that isn't going to be used.
selection String: A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing
null will return all rows for the given table.
selectionArgs String: You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they
appear in the selection. The values will be bound as Strings.
groupBy String: A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null
will cause the rows to not be grouped.
having String: A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING
clause (excluding the HAVING itself). Passing null will cause all row
groups to be included, and is required when row grouping is not being
used.
orderBy String: How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the
default sort order, which may be unordered.
limit String: Limits the number of rows returned by the query, formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Where clause and args work together to form the WHERE statement of the SQL query. So say you looking to express
WHERE Column1 = 'value1' AND Column2 = 'value2'
Then your whereClause and whereArgs will be as follows
String whereClause = "Column1 =? AND Column2 =?";
String[] whereArgs = new String[]{"value1", "value2"};
If you want to select all table columns, i believe a null string passed to tableColumns will suffice.
if your SQL query is like this
SELECT col-1, col-2 FROM tableName WHERE col-1=apple,col-2=mango
GROUPBY col-3 HAVING Count(col-4) > 5 ORDERBY col-2 DESC LIMIT 15;
Then for query() method, we can do as:-
String table = "tableName";
String[] columns = {"col-1", "col-2"};
String selection = "col-1 =? AND col-2=?";
String[] selectionArgs = {"apple","mango"};
String groupBy =col-3;
String having =" COUNT(col-4) > 5";
String orderBy = "col-2 DESC";
String limit = "15";
query(tableName, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
db.query(
TABLE_NAME,
new String[] { TABLE_ROW_ID, TABLE_ROW_ONE, TABLE_ROW_TWO },
TABLE_ROW_ID + "=" + rowID,
null, null, null, null, null
);
TABLE_ROW_ID + "=" + rowID, here = is the where clause. To select all values you will have to give all column names:
or you can use a raw query like this
db.rawQuery("SELECT * FROM permissions_table WHERE name = 'Comics' ", null);
and here is a good tutorial for database.
I'm working on an small android app that maintains a small database of tools which I lend out to other people.
As part of the app, I am incorporating an sqllite database, where I am having a bit of trouble performing queries and working with cursors once the queries have been executed.
The code in question is as follows:
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_NAME };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, columns,
selection, selectionArgs, null, null, null, null);
return Integer.parseInt(cursor.getString(3));
The contract for the database is as follows:
public class ToolStatisticContract {
public static final class ToolStatisticEntry implements BaseColumns {
public static final String TABLE_NAME = "tooltable";
public static final String COLUMN_TOOL_NAME = "toolName";
public static final String COLUMN_LIFESPAN = "lifespan";
public static final String COLUMN_USAGE = "usageTime";
}
}
I am essentially trying to extract out the value from COLUMN_USAGE, which seems to be producing errors with regards to parsing the value to an integer. The value in the COLUMN is actually an integer typecasted as a String from a previous segment of code, so I'm fairly certain the error is encompasssed with the code snippets above.
Thanks again in advance for all your help!
The code in question is as follows
The net SQL statement is something like:
SELECT toolName FROM tooltable WHERE toolName = ?
And there is no column with index 3, since you are only returning 1 column.
You need to:
Have usageTime in your column list (COLUMNS)
Move the Cursor to a valid row (as it initially is positioned before the first row)
Pass getInteger() the value that lines up with COLUMNS to retrieve usageTime
You could use the following. This uses null instead of columns, which will get all columns (i.e. resolves to SELECT * FROM table). It checks that a row has been returned and only then does it try to get the data. It also closes the cursor (you should close a cursor when done with it). It uses cursor.getInt() to get the integer value rather than convert it from a string to int. It assumes that you'll only get 1 row (if no rows then 0 will be returned).
int returnvalue = 0;
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_NAME };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, null,
selection, selectionArgs, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
returnvalue = cursor.getInt(2);
//or returnvalue = Integer.parseInt(cursor.getString(2));
}
cursor.close();
return returnvalue;
Note! I haven't checked this just coded it from memory, so apologies for the odd mistake.
To do the above using specific columns then you could use:-
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_USAGE };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, columns,
selection, selectionArgs, null, null, null, null);
In which case the column index would be 0 (that is the index is according to the column's in the cursor). However it might be better to use, the following which gets the column index according to the column's name:-
cursor.getInt(cursor.getColumnIndex(COLUMN_USAGE);
The easiest way to read a single value from the database is to use a helper function that allows you to avoid having to handle cursor objects:
String query = "SELECT usageTime FROM tooltable WHERE toolName = ?";
String[] selectionArgs = { tool };
long returnvalue = DatabaseUtils.longForQuery(mToolDb, query, selectionArgs);
i want to filter multiple data such as
id = "1,3,5" from columnid which is having 1 to 10 id
and another column such as name
name = "a,e,d" from name column of 10 records
and another criteria such as age
age = "21,23,20" from age column of 10 records from same table,
one example i got is
Cursor cursor = db.query("TABLE_NAME",new String[]{"ColumnName"}, "ColumnName=?",new String[]{"value"}, null, null, null);
which is just for one column but i want to get data from multiple column, can anyone help me?
try this working example,
Cursor cursor =
db.query(TABLE_DIARYENTRIES,
new String[] {},
STUDENT_ID + " IN ("+resultStudent+")"+ " AND " +CLASS_NAME + " IN ("+resultClass+")"
+ " AND " +SUBJECT_NAME + " IN ("+resultSubject+")"
null, null, null, null);
and your result string should be 'a','b','c'
I really like the way Google's example is structured. Because for noobies such as myself it makes it really clear what I am doing. And it is also more robust to SQL injections. Here is my modified version of the Google example:
//Column(s) I want returned
String[] projection = {"ColumnIWantReturned"};
//Column(s) I want to filer on
String selection = "FilterColumn1 IN (?) and FilterColumn2 IN (?, ?)";
String[] selectionArgs = {"ArgumentForFilterColumn1", "FirstArgumentForFilterColumn2", "SecondArgumentForFilterColumn2"};
Cursor cursor = db.query(
"MyTable", // The table to query
projection, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null // The sort order
);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Log.d("this-is-a-test", cursor.getString(0));
cursor.moveToNext();
}
cursor.close();
I have database which contains "date" column and "item" column.
I want that user could update specific row in the database.
I trying to do it with update method in SQLiteDatabase class.
My problem is that i dont know how to make update method find exactly the row i want.
I saw some example that use it with parameters from one word.
like this:
ourDatabase.update(tableName, cvUpdate, rowId + "=" + item , null);
My problem is that i want to update the row that have specific item and date. so the name of the item alone is not enough.
I tried this code below but its didnt work, hope youll can help me.
public void updateEntry(String item, String date) throws SQLException{
String[] columns = new String[]{myItem, myDate};
Cursor c = ourDatabase.query(tableName, columns, null, null, null, null, null);
long position;
ContentValues cvUpdate = new ContentValues();
cvUpdate.put(date, myDate);
cvUpdate.put(item, myExercise);
int itemAll = c.getColumnIndex(myItem);
int dateAll = c.getColumnIndex(myDate);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
if (c.getString(itemAll).equals(myItem) && c.getString(dateAll).equals(myDate))
{
position = c.getPosition();
break;
}
}
ourDatabase.update(tableName, cvUpdate, rowId + "=" + position , null);
}
First, the columns String[] is supposed to contain column names, such as "_ID", or whatever are the column names you have used. Given that you compare the content of the column myItem with the object myItem, I assume there is a confusion somewhere here.
Secondly, rowId and position are different things in SQL, especially if you delete rows, as the row id usually is autoincrement, and especially since your query is not explicitely sorted. Replacing c.getPosition() by c.getLong(c.getColumnIndex(ID_COLUMN)) would make more sense.
Thirdly, sql is nice because you can query it. For example, rather than get all items and loop to find the matching date and item, you can :
String whereClause = ITEM_COLUMN + " = ? and " + DATE_COLUMN + " = ?";
String[] whereArgs = new String[] { item, date };
Cursor c = ourDatabase.query(tableName, columns, whereClause, whereArgs, null, null, null);
instead of your for loop.
Forthly, you can even make the query in the update :
String whereClause = ITEM_COLUMN + " = ? and " + DATE_COLUMN + " = ?";
String[] whereArgs = new String[] { item, date };
ourDatabase.update(tableName, cvUpdate, whereClause, whereArgs);
Extra tip: use full caps variable names for contants such as column names, it help with readability.
this is my code used which i use for making method
String item = item1.getText().toString();
item = item.toLowerCase();
String date = getDate();
edited = new Datahelper(this);
edited.open();
String returnedprice = edited.getprice(item,date);
String returneddetail = edited.getdetail(item,date);
edited.close();
price.setText(returnedprice);
details.setText(returneddetail);
and this is my code of method that i am using for getting that string but here i dont know how to use the 2nd date string so that the string price that return is from a row that contains that item and that date.. please give me the code of how to do it..
public String getprice(String item ,String date) {
// TODO Auto-generated method stub
String[] columns = new String[]{KEY_ROWID,
KEY_CATEGORY,KEY_DATE,KEY_PRICE,KEY_DETAILS};
Cursor v =ourDatabase.query(DATABASE_TABLE, columns, KEY_CATEGORY + " ='" + item
+"'",null,null, null, null);
if(v!=null){
String price = v.getString(3);
return price;
}
return null;
}
public String getdetail(String item,String date) {
// TODO Auto-generated method stub
String[] columns = new String[]{KEY_ROWID,
KEY_CATEGORY,KEY_DATE,KEY_PRICE,KEY_DETAILS};
Cursor v =ourDatabase.query(DATABASE_TABLE, columns, KEY_CATEGORY + " ='" + item +
"'",null,null, null, null);
if(v!=null){
String detail = v.getString(4);
return detail;
}
return null;
}
So probably you want to use two arguments in select query so:
You can use two methods:
rawQuery()
query()
I will give you basic example for both cases.
First:
String query = "select * from Table where someColumn = ? and someDateColumn = ?";
Cursor c = db.rawQuery(query, new String[] {textValue, dateValue});
Explanation:
So i recommend to you use ? that is called placeholder.
Each placeholder in select statement will be replaced(in same order so first placeholder will be replaced by first value in array etc.) by values from selectionArgs - it's String array declared above.
Second:
rawQuery() method was easier to understand so i started with its. Query() method is more complex and has a little bit more arguments. So
columns: represents array of columns will be selected.
selection: is in other words where clause so if your selection is
KEY_COL + " = ?" it means "where " + KEY_COL + " = ?"
selectionArgs: each placeholder will be replaced with value from this
array.
groupBy: it's multi-row (grouping) function. more
about
having: this clause is always used with group by clause here is
explanation
orderBy: is clause used for sorting rows based on one or multiple
columns
Also method has more arguments but now you don't need to care about them. If you will, Google will be your friend.
So let's back to explanation and example:
String[] columns = {KEY_COL1, KEY_COL2};
String whereClause = KEY_CATEGORY " = ? and " + KEY_DATE + " = ?";
String[] whereArgs = {"data1", "data2"};
Cursor c = db.query("Table", columns, whereClause, whereArgs, null, null, null);
So whereClause contains two arguments with placeholder for each. So first placeholder will be replaced with "data1" and second with "data2".
When query is performed, query will look like:
SELECT col1, col2 FROM Table WHERE category = 'data1' AND date = 'data2'
Note: I recommend to you have look at Android SQLite Database and ContentProvider - Tutorial.
Also i recommend to you an usage of placeholders which provide safer and much more readable and clear solutions.
You should read any SQL tutorial to find out what a WHERE clause it and how to write it.
In Android, the selection parameter is the expression in the WHERE clause.
Your query could be written like this:
c = db.query(DATABASE_TABLE, columns,
KEY_CATEGORY + " = ? AND " + KEY_DATE + " = ?",
new String[] { item, date },
null, null, null);