I followed advice in this question, but for my purposes I don't want a WHERE.
I don't know the value, so I cannot say rawQuery("... WHERE x = ?", y), I don't care what y is, it's just a cell I want, and it is known that there is a single row.
If it is not possible to lose the condition (perhaps because of causing an indeterminate number of results?) - then how can I say "from column z and row 0"?
I'm lacking either terminology, or outright understanding, because my searches are turning up nothing.
Edit: Eclipse doesn't complain at:
result = db.rawQuery("SELECT col FROM tbl", my_unused_string_array);
I'm not at a testing stage yet, and I can't enter this into the SQL db reader I was using to test SELECT col FROM tbl and ~ with WHERE.. will it work?
As per your edit, you don't need to specify WHERE clause, if you want to get all the records from a table:
result = db.rawQuery("SELECT col FROM tbl", new String[0]);
The SQL query "SELECT * FROM table" will return the entire table. "SELECT colX, colY FROM table" will return columns colX and colY for all the rows in the table. If your table contains just one row, "SELECT col FROM table" will return the value of col for that one row.
To use the SQLiteDatabase API to make that query, you would say:
result = db.rawQuery("SELECT col FROM tbl", null);
... because you are not supplying any query parameters.
Assuming that there is just one row seems dangerous to me. I would not use the "LIMIT" clause, because, while that will always get one row, it will hide the fact that there is more than one row, if that happens. Instead, I suggest that you assert that the cursor contains one row, like this:
if (1 != result.getCount()) {
throw Exception("something's busted");
}
Instead of Raw query use
Cursor cur = db.query(Table_name, null, null, null, null,
null, null);
and get the desired attributes from cursor.
where the query method has parameters in following manner:
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
Parameters:
table The table name to compile the query against.
columns 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 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 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 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 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 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.
Returns
A Cursor object, which is positioned before the first entry.
Related
Since the db does not have create date and some ordering field (but in my observation the last row is the latest record),
so how can i get the five last record in some condition e.g.
five record that their schoolid == 1?
Thanks
public Cursor select()
{
String orderBy = FIELD_pubKey+" DESC";
Cursor cursor = iReadDatabase.query(TABLE_NAME, null, null, null, null, null, orderBy);
cursor.moveToFirst();
return cursor;
}
There's no such thing as a last record or a first or a 42nd.
Which records appears last in the result of a query is dependent on the query plan, or an Explicit order by if you add one.
Select * From Table Where ...
The rows will be returned in whatever order the engine considers suitable at the time.
If you need them in specific order, then add an order by clause to the query, anything else is asking for it.
Something like
Select * From Table Order by SomeColumn desc limit 5
will do what you require.
Now what column you need to order by I've no idea, but you need one that will do the job, assuming automatic primary key, but note it is possible to mess with that.
In Android, android.database.sqlite.SQLiteStatement allows me to use prepared statements in SQLite to avoid injection attacks. Its execute method is suitable for create/update/delete operations, but there does not seem to be any method for queries that returns a cursor or the like.
Now in iOS I can create prepared statements of type sqlite3_stmt* and use them for queries, so I know this is not a limitation of SQLite. How can I perform queries with prepared statements in Android?
a prepared statement allows you to do two things
speed up the performance since the database does not need to parse the statement each time
bind & escape arguments in the statement so you are save against injection attacks
I don't know exactly where/when Androids SQLite implementation actually uses sqlite3_prepare (afiak not sqlite3_prepare_v2 - see here) but it does use it otherwise you could not get Reached MAX size for compiled-sql statement cache errors.
So if you want to query the database you have to rely on the implementation there is no way I know of to do it with SQLiteStatement.
Regarding the injection safety, every database query, insert, etc method has (sometimes alternative) versions that allow you to bind arguments.
E.g. if you want to get a Cursor out of
SELECT * FROM table WHERE column1='value1' OR column2='value2'
Cursor SQLiteDatabase#rawQuery(
String sql, : full SELECT statment which can include ? everywhere
String[] selectionArgs : list of values that replace ?, in order they appear
)
Cursor c1 = db.rawQuery(
"SELECT * FROM table WHERE column1=? OR column2=?",
new String[] {"value1", "value2"}
);
Cursor SQLiteDatabase#query (
String table, : table name, can include JOIN etc
String[] columns, : list of the columns required, null = *
String selection, : WHERE clause withouth WHERE can / should include ?
String[] selectionArgs, : list of values that replace ?, in order they appear
String groupBy, : GROUP BY clause w/o GROUP BY
String having, : HAVING clause w/o HAVING
String orderBy : ORDER BY clause w/o ORDER BY
)
Cursor c2 = db.query("table", null,
"column1=? OR column2=?",
new String[] {"value1", "value2"},
null, null, null);
Via ContentProviders - that case is slightly different since you interact with an abstract provider, not a database. There is acutally no guarantee that there is a sqlite database backing the ContentProvider. So unless you know what columns there are / how the provider works internally you should stick to what the documentation says.
Cursor ContentResolver#query(
Uri uri, : an URI representing the data source (internally translated to a table)
String[] projection, : list of the columns required, null = *
String selection, : WHERE clause withouth WHERE can / should include ?
String[] selectionArgs, : list of values that replace ?, in order they appear
String sortOrder : ORDER BY clause w/o ORDER BY
)
Cursor c3 = getContentResolver().query(
Uri.parse("content://provider/table"), null,
"column=? OR column2=?",
new String[] {"value1", "value2"},
null);
Hint: if you want to LIMIT here you can add it to the ORDER BY clause:
String sortOrder = "somecolumn LIMIT 5";
or depending on the implementation of the ContentProvider add it as a parameter to the Uri:
Uri.parse("content://provider/table?limit=5");
// or better via buildUpon()
Uri audio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
audio.buildUpon().appendQueryParameter("limit", "5");
In all cases ? will be replaced by the escaped version of what you put in the bind argument.
? + "hack'me" = 'hack''me'
I have a listview populated from an SQLite database. I have several items that I successfully populate into the listview, however I'm having trouble with one last thing.
I'm trying to queue the sum total of the column KEY_CONTENT6 which is a string type, however it only contains numbers. I'd like to keep it as a string, so to add it up I'm using Double.valueOf(). The problem is this code force closes on queue and I cant figure out whats wrong:
public Cursor queueAll(){
String[] columns =
new String[]{KEY_ID, "sum("+ Double.valueOf(KEY_CONTENT6) +")",
KEY_CONTENT9, KEY_CONTENT10 };
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null , null, KEY_CONTENT10, null, KEY_CONTENT9+ " DESC");
return cursor;
}
simply use SUM, no need to use anything else..
String[] columns =
new String[]{KEY_ID, "sum(KEY_CONTENT6)",
KEY_CONTENT9, KEY_CONTENT10 };
It is valid for SQLite. Because, no matter what you set data type in SQLite, it stores values as string. So, type conversion is somewhat built-in in SQLite.
You can't use java in a SQL statement, either stick to strait sql or iterate over the cursor and use java to do your calculation.
You can find everything there is to know about sqlite here http://www.sqlite.org/docs.html
SQLite is basically typeless, so you might be able to use SUM on your column even though it is a string. However, if it's meant to be a numeric column, why not give it a number type??
I have been trying to use the character wild card "_" in sqlite where conditions and am close to "jumping off a high place" I have tried both rawQuery and query with a variety of hard and soft coded parameters. It seems to ignores the character wild card "_"and returns all rows or none at all.
The data held is in several columns representing a features of an oblect for example a column may represent the colours of an object
("red,orange,yellow,green,blue,indego,violet,black")
and a row's colour could be "01001000" meaning that it is orange and blue but not red, yellow etc. other columns contain single characters ie size contains s,m or l (mapping small, medium, large ) the database holds several columns of each type, the idea to have as compact a database as possible.
My first intention was to code by passing the 'where' of my select as a string to the rawQuery(myselect,null) where the myselect was compiled in the code in response to several features selected by the user.
ie
the mywhere string is compiled to return :-
colour1 like "_1__10__" and colour2 like "___1_01__" and size ="l"
and passed to the rawQuery
db.rawQuery("SELECT _id , name FROM widgets WHERE " + mywhere , null);
The statement below works fine using Firefox's SQLite Manager
SELECT _id , name FROM widgets WHERE colour1 like "_1__10_" and colour2 like "__1_01___" and size ="m"
In order to investigate I have cut the query down to one column in the where clause
myselect ="SELECT _id ,name,FROM widgets where colour1 like \"1_______\"";
cursor = db.rawQuery(myselect,null);
returns no rows
myselect ="SELECT _id ,name,FROM widgets where colour1 like \"%1_______%\"";
cursor = db.rawQuery(myselect,null);
returns rows but not all have a 1 at the first char ( I expected this )
myselect ="SELECT _id ,name, FROM widgets where colour1 like ?";
String[] whereArguments = { "1_______" };
cursor = db.rawQuery(myselect,whereArguments);
returns no rows
myselect ="SELECT _id ,name, FROM widgets where colour1 like ?";
String[] whereArguments = { "%1_______%" };
cursor = db.rawQuery(myselect,whereArguments);
returns rows but not all have a 1 at the first char
But I dont get any rows from
myselect ="SELECT _id ,name, FROM widgets where colour1 like ?";
String[] whereArguments = { "10000000" };
cursor = db.rawQuery(myselect,whereArguments);
and there are rows containing "10000000"
Does any one have any solutions? I have tried searching but it seems that rawQuery and query have questionable functionality in Android.
Not sure if this is your main source of problems, but the string delimiter in SQLite is the single quote character (') not the double quote one ("). See this, for example.
How do I get the row ID from a Cursor?
I don't think the Cursor exposes this directly.
SQLiteDatabase.insert() returns the row id of the newly inserted row. Or in Android the convention is that there is a column named "_id" that contains the primary autoincrement key of the table. So cursor.getLong(cursor.getColumnIndex("_id")) would retrieve this.
I had this same problem where the column index for the primary key was reported as -1 (meaning it isn't there). The problem was that I forgot to include the _ID column in the initial SELECT clause that created the cursor. Once I made sure it was included, the column was accessible just like any of the others.
Concerning the last sentence of Nic Strong's answer,following command didn't work for me. cursor.getColumnIndex("_id") was still -1
cursor.getLong(cursor.getColumnIndex("_id"))
Maybe there's some other issue in my configuration that's causing the problem?
Personally I've taken to maintaining my own custom unique id column in each table I create; A pain, but it gets around this issue.
return sqlite_db.query(table, new String[] { "rowid", "*" }, where, args, null, null, null);
In my case I have "rowid" in DataManager.FIELD_ID and this is SQLite identity column (each table in sqlite has this special kind of column), so I don't need any of my own custom unique id column in tables.
Cursor cursor = mySQLiteHelper.getReadableDatabase().query(TABLE_NAME, new String[] { "ROWID", "*" }, where, null, null, null, null);
then
long rowId = cursor.getLong(0);
As long as the TABLE is not defined using WITHOUT ROWID you can get the ROWID (or should that be rowid see below for case) if you specify it as a column to be retrieved.
For example for a table with 3 defined columns (Names, Colour and Age) with no conventional _id column. The following rawQuery works and returns the ROWID :-
Cursor csr = db.rawQuery("SELECT Names, Colour, Age, ROWID FROM " + TABLE_NAME,null);
Note! that the column name in the cursor is lowercase as per :-
Note! ROWID in the SELECT SQL is case independent (e.g. RoWiD works).
Using
Cursor csr = db.rawQuery("SELECT * FROM " + TABLE_NAME,null);
WILL NOT return the ROWID (likewise for null for the columns when using the query method).
Using query (as opposed to rawQuery) works in the same way, that is you need to specifiy ROWID (note alternatives to ROWID below) as a column to be retrieved e.g. :-
Cursor csr = db.query(TABLE_NAME,new String[]{
"OiD",
"Names",
"Colour",
"Age"
},null,null,null,null,null);
Alternatives to ROWID
Instead of ROWID, you can also use _ROWID_ or OID (case independent) as the column name in the query noting that the column name in the resultant cursor is rowid i.e. it is lowercase.