I would like to implement a SQL-Query that gives me a range of entries. Example:
public List<Entry> getEntries(int lowerValue, int upperValue){
//Select upper - lower entries.
}
getEntries(0, 20) --> First 20 Entries
getEntries(21, 40) --> Entry 21 to 40
getEntries(12, 200) --> Entry 12 to 200
At the moment I get all entries like this:
public List<Log> getLogs(){
List<Log> list = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
String query = "SELECT * FROM " + TABLE_LOGS + " WHERE 1";
//Cursor points to a location in your results
Cursor c = db.rawQuery(query, null);
//Move to the first row in your results
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("type")) != null) {
int id = c.getInt(c.getColumnIndex("_id"));
int type = c.getInt(c.getColumnIndex("type"));
long date = c.getLong(c.getColumnIndex("date"));
int refId = c.getInt(c.getColumnIndex("refId"));
String extra = c.getString(c.getColumnIndex("extra"));
list.add(new Log(id, type, date, refId, extra));
}
c.moveToNext();
}
db.close();
c.close();
return list;
}
I know there is a LIMIT clause, but that starts always from the first entry.
What you need is the combination of LIMIT and OFFSET
You could use
LIMIT <skip>, <count>
or
LIMIT <count> OFFSET <skip>
So some examples would be
"SELECT * FROM " + TABLE_LOGS + " WHERE type=1 LIMIT 20 OFFSET 0"
"SELECT * FROM " + TABLE_LOGS + " WHERE type=1 LIMIT 20 OFFSET 20"
"SELECT * FROM " + TABLE_LOGS + " WHERE type=1 LIMIT 20 OFFSET 40"
Hope this helps.
Related
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)
I have some code like this:
public void gameOverCheck() {
SQLiteDatabase database = this.getWritableDatabase();
database.execSQL("SELECT " + COL_ROLE + " COUNT");
database.close();
}
in android. And would like to count the values of COL_ROLE (which has one of two possible values (mafia, civilian)). So if the number of Mafia >= Civilian game = mafias win. If Mafias = 0, game = civilian won. I am struggling with the SQL command to do the first part, am I supposed to group the values?
Try this:
Cursor mCount= db.rawQuery("select count(*) from your_table where " + COL_ROLE + " = 'mafia'", null);
mCount.moveToFirst();
int count = mCount.getInt(0);
mCount.close();`
i want to get the first 60 rows, than the next 60....
This is my Cursor
final Cursor cursor = myDbSales.searchNamemagic(name, startLong, endLong, limita, limitb);
public Cursor searchNamemagic(String search_str, String startdate, String enddate, String limita , String limitb) {
try {
int firstSpace = search_str.indexOf(" "); // detect the first space character
firstName = search_str.substring(0, firstSpace); // get everything upto the first space character
lastName = search_str.substring(firstSpace).trim(); // get everything after the first space, trimming the spaces off
}catch (Exception c){}
String query = "SELECT * , strftime('%d.%m.%Y %H:%M', datetime(timeStamp, 'unixepoch', 'localtime')) as timecrazy , tastepreis/(tax+100.0)*tax as'"+TAXSUMSEARCHNAME+"', '"+currency+"' as '"+ DOLLA_SIGN+"' FROM salesTable where timeStamp BETWEEN '"+startdate+"' AND '"+enddate+"' AND (sellid LIKE '%"+search_str+"%' OR tastemodel LIKE '%"+search_str+"%' OR bezeichnung LIKE '%"+search_str+"%' OR sellid LIKE '%"+lastName+" "+firstName +"%' ) ORDER BY timeStamp DESC limit '"+limita+"', '"+limitb+"' " ;
Cursor mCursor = dbSales.rawQuery(query, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
And this is my method
method(name,imyourlist1,"0","60" );
method(name,imyourlist2, "60","120" );
method(name,imyourlist3, "120","180");
method(name,imyourlist4, "180","240");
method(name,imyourlist5, "240","300");
v(name,imyourlist6, "300","360");
method(name,imyourlist7, "360","420");
method(name,imyourlist8, "420","480");
method(name,imyourlist9 ,"480","540");
method(name,imyourlist10 ,"540","600" );
private void method (String name ,ListView imyourlist2, String limita, String limitb){
final Cursor cursor = myDbSales.searchNamemagic(name, startLong, endLong, limita, limitb)
imyourlist1 is correct with 60 Rows but the next ones get more.
For example first one = 0-60 next one 60-more than 120
Is maybe my limit wrong?
You can use this script
SELECT * FROM tableName LIMIT 60 OFFSET 0
Next 60
SELECT * FROM tableName LIMIT 60 OFFSET 1
Page Number is int
SELECT * FROM tableName LIMIT 60 OFFSET Number
I have a table with events, and want to select all events which happen from three days ago. (The events do belong to categories which is a field in the Article table which has to description etc., but that works).
This is my code:
public List<Event> findByCategory(long catId, int start, int count) throws Exception {
String limit = "";
if (count > 0) limit = start + "," + count;
SQLiteQueryBuilder _QB = new SQLiteQueryBuilder();
_QB.setTables("Event e INNER JOIN Article a ON e.articleId=a.id");
String[] rows = _fields.keySet().toArray(new String[0]);
for (int i = 0; i < rows.length; i++) {
rows[i] = "e." + rows[i];
}
Cursor cursor = _QB.query(_db, rows, "date(e.startTime) > date('now','-3 days') AND EXISTS(SELECT * FROM CategoryArticleLink WHERE CategoryArticleLink.articleId = a.id AND EXISTS (SELECT * FROM Category WHERE Category.id = CategoryArticleLink.categoryId AND Category.id = '" + catId + "'))", null, null, null, "e.startTime ASC", limit);
List<Event> list = new ArrayList<>(cursor.getCount());
if (cursor.moveToFirst()) {
do {
Event item = getObject(cursor);
list.add(item);
} while (cursor.moveToNext());
}
cursor.close();
return list;
}
The resulting Query is:
SQLiteQuery: SELECT e.articleId, e.keynote, e.locationId, e.id, e.finishTime, e.startTime, e.languageCode, e.flag, e.lastUpdate FROM Event e INNER JOIN Article a ON e.articleId=a.id WHERE (date(e.startTime) > date('now','-3 days') AND EXISTS(SELECT * FROM CategoryArticleLink WHERE CategoryArticleLink.articleId = a.id AND EXISTS (SELECT * FROM Category WHERE Category.id = CategoryArticleLink.categoryId AND Category.id = '9'))) ORDER BY e.startTime ASC LIMIT 0,8
This returns an empty result set. However, if I take the date selection (date(e.startTime) > date('now','-3 days')) out of the query it returns all records as expected. So I must be doing something small wrong, but I just don't see what.
The field type on database generation is 'DATE', so that should be ok I expect.
The correct code in my setup is 'date(e.startTime / 1000, 'unixepoch') > date('now','-3 day')'. I use Date().getTime() to save the date/time as a long. But have uses a timestamp a 1000x larger then normal.
Moreover, the 'unixepoch' seems to be a needed addition in the date function.
I have the following code...
protected long getNumQueuedChunks(boolean distinctEntries) throws Exception {
SQLiteDatabase db = null;
try {
db = dbhelper.getReadableDatabase();
String whereClause = C_STATUS + " = ? AND " + C_NUM_FAILURES + " < ?";
String[] whereArgs = new String[] {STATUS_AWAITING_PROCESSING, 10};
long count = DatabaseUtils.queryNumEntries(db, QUEUE_TABLE_NAME, whereClause, whereArgs);
return count;
}
finally {
try {
db.close();
}
catch(Exception ignore) {
}
}
}
...which works fine if I want to return the total amount of rows that match the WHERE condition.
However, I would like to only count records that have distinct/unique combinations of data across these 3 columns: C_URI, C_BYTE_START_NUM and C_NUM_BYTES.
I know I could do something like...
String[] columns = {C_URI, C_BYTE_START_NUM, C_NUM_BYTES};
String whereClause = C_STATUS + " = ? AND " + C_NUM_FAILURES + " < ?";
String[] whereArgs = new String[] {STATUS_AWAITING_PROCESSING, "10"};
Cursor c = db.query(true, QUEUE_TABLE_NAME, columns, whereClause, whereArgs, null, null, null, null);
int count = c.getCount();
...but I am hoping there is a more efficient way to perform a distinct count in this situation??
Just to add clarity, if I have this data in my table...
C_URI | C_BYTE_START_NUM | C_NUM_BYTES
1.jpg | 0 | 1024
1.jpg | 1024 | 1999
2.jpg | 0 | 500
2.jpg | 0 | 500
...the result of the distinct count should be 3.
NB - I have seen a similar requirement described here (second answer) but that doesn't help me as I am wanting to do a distinct count across 3 columns rather than just one.
The most efficient way of counting records is to let the database do this:
SELECT COUNT(*)
FROM (SELECT DISTINCT Uri,
ByteStartNum,
NumBytes
FROM QueueTable)
(With the separate subquery, it does not matter if you use DISTINCT or GROUP BY over the three columns.)
This query does not fit into the constraints of one of the helper functions like query or queryNumEntries, so you have to construct the entire SQL statement by hand:
long getNumQueuedChunks() {
SQLiteDatabase db = dbhelper.getReadableDatabase();
try {
String query = "SELECT COUNT(*) FROM " +
"(SELECT DISTINCT " + C_URI + "," + C_BYTE_START_NUM + "," + C_NUM_BYTES +
" FROM " + QUEUE_TABLE_NAME +
" WHERE " + C_STATUS + " = ?" +
" AND " + C_NUM_FAILURES + " < 10)";
String[] args = new String[] { STATUS_AWAITING_PROCESSING };
return DatabaseUtils.longForQuery(db, query, args);
} finally {
db.close();
}
}
Have you tried the SQLiteDatabase.rawQuery() method? You can put a raw SQL query in it, for example, something like:
select distinct C_URI, C_BYTE_START_NUM, C_NUM_BYTES from MyTable
The method returns a Cursor, and you can immediately get the count from the cursor object. Of course, you can specify a where clause if you want to as well. Then free up the Cursor once you got your count.