This question already has answers here:
Specifying limit / offset for ContentProvider queries
(4 answers)
Closed 4 years ago.
Is there a way to limit the number of rows returned from content provider?
I found this solution, however, it did not work for me. All of the rows are still being returned.
Uri uri = Playlists.createIdUri(playlistId); //generates URI
uri = uri.buildUpon().appendQueryParameter("limit", "3").build();
Cursor cursor = activity.managedQuery(playlistUri, null, null, null, null);
I have had this issue and had to break my head till I finally figured it out, or rather got a whay that worked for me. Try the following
Cursor cursor = activity.managedQuery(playlistUri, null, null, null, " ASC "+" LIMIT 2");
The last parameter is for sortOrder. I provided the sort order and also appended the LIMIT to it. Make sure you give the spaces properly. I had to check the query that was being formed and this seemed to work.
Unfortunately, ContentResolver can't query having limit argument. Inside your ContentProvider, your MySQLQueryBuilder can query adding the additional limit parameter.
Following the agenda, we can add an additional URI rule inside ContentProvider.
static final int ELEMENTS_LIMIT = 5;
public static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher( UriMatcher.NO_MATCH );
........
uriMatcher.addURI(AUTHORITY, "elements/limit/#", ELEMENTS_LIMIT);
}
Then in your query method
String limit = null; //default....
switch( uriMatcher.match(uri)){
.......
case ELEMENTS_LIMIT:
limit = uri.getPathSegments().get(2);
break;
......
}
return mySQLBuilder.query( db, projection, selection, selectionArgs, null, null, sortOrder, limit );
Querying ContentProvider from Activity.
uri = Uri.parse("content://" + ContentProvider.AUTHORITY + "/elements/limit/" + 1 );
//In My case I want to sort and get the greatest value in an X column. So having the column sorted and limiting to 1 works.
Cursor query = resolver.query(uri,
new String[]{YOUR_COLUMNS},
null,
null,
(X_COLUMN + " desc") );
A content provider should on general principle pay attention to a limit parameter.
Unfortunately, it is not universally implemented.
For instance, when writing a content provider to handle SearchManager queries:
String limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT);
Where it isn't implemented you can only fall back on the ugly option of gluing a limit on the sort clause.
Related
How can I query CalendcarContract.Instances with a LIMIT clause?
I would like to query starting with a particular start date for a LIMIT of "n" rows.
What I've tried is:
final Uri uri = Uri.parse(CalendarContract.Instances.CONTENT_URI + "/" +
Long.toString(startDate) + "/" +
Long.MAX_VALUE);
final String sortOrder = Instances.BEGIN;
String selection = " limit " + rows;
Cursor cursor = context.getContentResolver().query (
uri,
projection,
selection,
null,
sortOrder);
This generates an error, reported in the log file:
...while compiling: SELECT Instances._id...WHERE (begin<=? AND end>=? AND (limit 1)...
I believe the error is the "AND" before (limit 1). The service is adding that, not me. So, is there another URI I can use or another technique?
NB: I specifically want the Instances versions, which joins single events with recurring events.
Thanks.
Ok, never mind unless you have a better answer.
I realized this is a more general URI problem, not specifically related to CalendarContract. In searching for other results, I found one suggestion to append LIMIT n to the sort clause, e.g.
final String sortOrder = Instances.BEGIN + " limit " + 10;
Credit to
How to add limit clause using content provider
I'm writing a method to update default settings in a table. The table is very simple: two columns, the first containing labels to indicate the type of setting, the second to store the value of the setting.
At this point in the execution, the table is empty. I'm just setting up the initial value. So, I expect that this cursor will come back empty. But instead, I'm getting an error (shown below). The setting that I am working with is called "lastPlayer" and is supposed to get stored in the "SETTING_COLUMN" in the "SETTINGS_TABLE". Here's the code:
public static void updateSetting(String setting, String newVal) {
String table = "SETTINGS_TABLE";
String[] resultColumn = new String[] {VALUE_COLUMN};
String where = SETTING_COLUMN + "=" + setting;
System.err.println(where);
SQLiteDatabase db = godSimDBOpenHelper.getWritableDatabase();
Cursor cursor = db.query(table, resultColumn, where, null, null, null, null);
System.err.println("cursor returned"); //I never see this ouput
\\more
}
sqlite returned: error code = 1, msg = no such column: lastPlayer
Why is it saying that there is no such column lastPlayer? I thought that I was telling the query to look at the column "SETTING_COLUMN" and return the record where that column has a value "lastPlayer". I'm confused. Can somebody straighten me out? I've been looking a this for an hour and I just don't see what I am doing wrong.
Thanks!
You're not properly building/escaping your query. Since the value lastPlayer is not in quotes, your statement is checking for equality of two columns, which is what that error message is saying.
To properly build your query, it's best to not do this manually with String concatenation. Instead, the parameter selectionArgs of SQLiteDatabase.query() is meant to do this.
The parameters in your query should be defined as ? and then filled in based on the selectionArgs. From the docs:
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.
So, your code would look like this:
String where = SETTING_COLUMN + " = ?";
Cursor cursor = db.query(table, resultColumn, where, new String[] { setting }, null, null, null);
Is there a way to limit the result retrieved from mediastore using managedQuery function on Android. Since I currently have a grid that displaying all photos found on the sd card but it is too intensive of fetching it so I decide to limit the result retrieved from the media store but could not find a limit function that can reduce the resulting set of data.
Please help
use order in contentresolver's query method to implement your function,
such as 'columnname asc limit number'
in my case:
cursor = resolver.query(STORAGE_URI, projection,
Media.BUCKET_DISPLAY_NAME + "=?",
new String[] { folderName },
" _id asc limit " + num);
You can limit the result using the sortOrder parameter in query method. Something like this
ContentResolver contentResolver = getContentResolver();
Cursor androidCursor = null;
String sortOrder = String.format("%s limit 100",BaseColumns._ID);
androidCursor = contentResolver.query(IMAGE_URI,PROJECTION, null, null, sortOrder);
This will order the result set by id and limit the result.
When targeting Android 11 the suggested answer will cause an exception, with java.lang.IllegalArgumentException: Invalid token LIMIT
Instead you should provide a "limit" query parameter on the URI that the MediaProvider will read.
val queryUri = IMAGE_URI.buildUpon().appendQueryParameter("limit", limit.toString()).build()
I haven't found documentation for this, but it's present in the sources
I query and get a result set back, but I need to do some calculations that are impossible in the SQLite WHERE clause in order to determine what shows up in the ListView. How can I remove certain rows from the cursor? I know it is the same question as this Filter rows from Cursor so they don't show up in ListView but that answer does not help. Can an example be provided if there isn't a simpler way to do this?
It might work to simply retain all the rows in the Cursor, but then use a custom adapter to hide the unwanted rows at display time. For example, if you extend CursorAdapter, then you might have something like this in your bindView implementation:
View v = view.findViewById(R.id.my_list_entry);
boolean keepThisRow = .......; // do my calculations
v.setVisibility(keepThisRow ? View.VISIBLE : View.GONE);
There should be a better way to do this, but what I ended up doing is storing the ID of each row I wanted in a string ArrayList, and then requerying where _id IN arraListOfIds.toString(), replacing the square brackets with parentheses to fit SQL syntax.
// Get all of the rows from the database
mTasksCursor = mDbHelper.fetchAllTasks();
ArrayList<String> activeTaskIDs = new ArrayList<String>();
// calculate which ones belong
// .....
if (!hasCompleted)
activeTaskIDs.add(mTasksCursor.getString(TaskerDBadapter.INDEX_ID));
// requery on my list of IDs
mTasksCursor = mDbHelper.fetchActiveTasks(activeTaskIDs);
public Cursor fetchActiveTasks(ArrayList<String> activeTaskIDs)
{
String inClause = activeTaskIDs.toString();
inClause = inClause.replace('[', '(');
inClause = inClause.replace(']', ')');
Cursor mCursor = mDb.query(true, DATABASE_TABLE, columnStringArray(),
KEY_ROWID + " IN " + inClause,
null, null, null, null, null);
if (mCursor != null) { mCursor.moveToFirst(); }
return mCursor;
}
ContentResolver cr = getContentResolver();
Cursor groupCur = cr.query(
Groups.CONTENT_URI, // what table/content
new String [] {Groups._ID, Groups.NAME}, // what columns
"Groups.NAME NOT LIKE + 'System Group:%'", // where clause(s)
null, // ???
Groups.NAME + " ASC" // sort order
);
The "What Columns" piece above is where you can tell the cursor which rows to return. Using "null" returns them all.
I need to do some calculations that
are impossible in the SQLite WHERE
clause
I find this very hard to believe; my experience has been that SQL will let you query for just about anything you'd ever need (with the exception of heirarchical or recursive queries in SQLite's case). If there's some function you need that isn't supported, you can add it easily with sqlite_create_function() and use it in your app. Or perhaps a creative use of the SELECT clause can do what you are looking for.
Can you explain what these impossible calculations are?
EDIT: Nevermind, checking out this webpage reveals that the sqlite_create_function() adapter is all closed up by the Android SQLite wrapper. That's annoying.
I have a query that selects rows in a ListView without having a limit. But now that I have implemented a SharedPreferences that the user can select how much rows will be displayed in the ListView, my SQLite query doesn't work. I'm passing the argument this way:
return wDb.query(TABELANOME, new String[] {IDTIT, TAREFATIT, SUMARIOTIT}, CONCLUIDOTIT + "=1", null, null, null, null, "LIMIT='" + limite + "'");
The equals (=) operator is not used with the LIMIT clause. Remove it.
Here's an example LIMIT query:
SELECT column FROM table ORDER BY somethingelse LIMIT 5, 10
Or:
SELECT column FROM table ORDER BY somethingelse LIMIT 10
In your case, the correct statement would be:
return wDb.query(TABELANOME, new String[] {IDTIT, TAREFATIT, SUMARIOTIT}, CONCLUIDOTIT + "=1", null, null, null, null, String.valueOf(limite));
Take a look here at the SQLite select syntax: http://www.sqlite.org/syntaxdiagrams.html#select-stmt
This image is rather useful: http://www.sqlite.org/images/syntax/select-stmt.gif
For anyone stumbling across this answer looking for a way to use a LIMIT clause with an OFFSET, I found out from this bug that Android uses the following regex to parse the limit clause of a query:
From <framework/base/core/java/android/database/sqlite/SQLiteQueryBuilder.java>
LIMIT clause is checked with following sLimitPattern.
private static final Pattern sLimitPattern = Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
Note that the regex does accept the format offsetNumber,limitNumber even though it doesn't accept the OFFSET statement directly.
Due to this bug which also doesn't allow for negative limits
8,-1
I had to use this workaround
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(table);
String query = builder.buildQuery(projection, selection, null, null, null, sortOrder, null);
query+=" LIMIT 8,-1";