Distinct CONTACT_ID from ContactsContract.Data - android

I need to make a query to ContactsContract.Data table and values in CONTACT_ID column would be different (distinct).
Code:
final Uri uri = ContactsContract.Data.CONTENT_URI;
final String[] projection = new String[] {//
ContactsContract.Data.CONTACT_ID, //
ContactsContract.Data._ID, //
ContactsContract.Data.DISPLAY_NAME,//
ContactsContract.Data.LOOKUP_KEY //
};
final StringBuilder selectionBuilder = new StringBuilder();
selectionBuilder.append(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID);
selectionBuilder.append("= ? AND ");
selectionBuilder.append(ContactsContract.Data.MIMETYPE);
selectionBuilder.append("= ? ");
final String selection = selectionBuilder.toString();
final String[] selectionArgs = new String[] {//
String.valueOf(groupId), //
ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE //
};
return context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
First of all, I've tried to add "DISTINCT " to ContactsContract.Data.CONTACT_ID in projection. But there was an exception: java.lang.IllegalArgumentException: Invalid column DISTINCT contact_id
Then, I write this way:
"'DISTINCT "+ContactsContract.Data.CONTACT_ID+"'".
java.lang.IllegalArgumentException: Invalid column 'DISTINCT contact_id'
Then, I add to selectionBuilder:
selectionBuilder.append(" GROUP BY ").append(ContactsContract.Data.CONTACT_ID);
Once again, an exception: android.database.sqlite.SQLiteException: near "GROUP": syntax error: , while compiling: SELECT contact_id, _id, display_name, lookup FROM view_data_restricted data WHERE (1) AND (data1= ? AND mimetype= ? GROUP BY contact_id) ORDER BY display_name ASC
At last, I've append "group by" statement right after sortOrder, but:
android.database.sqlite.SQLiteException: near "GROUP": syntax error: , while compiling: SELECT contact_id, _id, display_name, lookup FROM view_data_restricted data WHERE (1) AND (data1= ? AND mimetype= ? ) ORDER BY display_name ASC GROUP BY contact_id
Is it ever possible to make query with distinct?
Maybe, I should append something to URI?

If you are targeting devices below ICS, you can use the GROUP_BY clause by adding a ) before the group by and a ( after:
selectionBuilder.append(") GROUP BY (")
As of ICS and above, the query interpretor is smarter and closes any unclosed parenthesis to prevent injection.
However, I don't see why you need distinct contact_ids here. A contact should probably have only one Data to make the association with one group, so you probably receive a different contact on each line.
Also, there may be something to do with http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#CONTENT_GROUP_URI it is not documented, but given its position, it may well be a direct access to Contacts belonging to a Group. You would use that Uri :
Uri uri = ContentUri.withAppendedId(ContactsContract.Contacts.CONTENT_GROUP_URI, groupId);
And then query it like the Contacts.CONTENT_URI

Related

Invalid token SELECT

Hi I am trying to get the content of bucket Id using content resolver in android Q I am getting this Error
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #7
Process: com.dev.newtermain, PID: 13048
java.lang.IllegalArgumentException: Invalid token SELECT
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:472)
at android.content.ContentResolver.query(ContentResolver.java:1183)
at android.content.ContentResolver.query(ContentResolver.java:1115)
at android.content.ContentResolver.query(ContentResolver.java:1071)
My Selection query is
selection = "bucket_id = ?) UNION SELECT _data, date_added, 0 as isImage FROM video WHERE (bucket_id = ?";
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
selectionArgs = new String[]{bucketIdString};
String[] projection = new String[]{
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_ADDED, MediaStore.Video.VideoColumns.DATE_ADDED
};
Cursor cur = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, MediaStore.Images.ImageColumns.DATE_ADDED + " DESC");
Any idea how I can fix this query
The selection parameter in ContentResolver::query does only support WHERE clauses (without the WHERE keyword). docs
Your approach is including the UNION clause in the selection which is invalid. If you need a union, you may have to do two separate queries and combine the two results yourself.
EDIT
For your specifc case the selection should be defined as follows
selection = "bucket_id = ?"
check out this selection
"SELECT _data, date_added, 0 as isImage FROM video WHERE bucket_id = ?";
removed bucket_id = ?) on start - this is just wrong, not proper format, doesn't fit to beginning of query...
removed following UNION as there is no union two selectors at all, just simple query for single video table
at the end removed unneeded opening bracket (WHERE (bucket_id = ? to WHERE bucket_id = ?)
but note that query is encapsulated and won't accept full single-string sqlite query, you have to split it for parts. variable selection would be "bucket_id = ?" for matching selectionArgs
also note that projection is a bit weird...
String[] projection = new String[]{
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_ADDED, MediaStore.Video.VideoColumns.DATE_ADDED
};
first two values are using MediaStore.Images instead of MediaStore.Video and all three doesn't match params in selection SELECT _data, date_added, 0 as isImage FROM - I see two params and one probably not needed static value
edit: I've just noticed you are selecting by Images - MediaStore.Images.Media.EXTERNAL_CONTENT_URI - but selection is pointing on video column... also I doubt that bucket_id column exists in MediaStore database, there is no such value in static declarations of columns... I would suggest you read a bit about sql and querying, because your snippet looks like every line is comming from another piece of code....

android.database.sqlite.SQLiteException: near "GROUP": syntax error (code 1 SQLITE_ERROR[1]): Android

I need to get phone Media data for custom app and i used query, but it shows error for some Android devices here my code and show syntax error only some devices.
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] PROJECTION_BUCKET = {
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.BUCKET_ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC};
String BUCKET_GROUP_BY =
"2) GROUP BY 2,(3";
String BUCKET_ORDER_BY = "MAX(datetaken) DESC";
// Get the base URI for the People table in the Contacts content provider.
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = getContext().getContentResolver().query(
images, PROJECTION_BUCKET, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY);
cursor.moveToNext();
String selection = "WHERE "+MediaStore.Images.Media.BUCKET_ID+" = 1030343353";
return new CursorLoader(getContext(), uri, PROJECTION_BUCKET, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY);
}```
and here error
android.database.sqlite.SQLiteException: near "GROUP": syntax error (code 1 SQLITE_ERROR[1]): , while compiling: SELECT _id, bucket_id, bucket_display_name, datetaken, _data, mini_thumb_magic FROM images WHERE ((is_pending=0) AND (is_trashed=0) AND (volume_name IN ( 'external_primary' )) AND (_data>'')) AND ((2) GROUP BY 2,(3)) ORDER BY MAX(datetaken) DESC
There is no easy fix to your problem. If you look here https://developer.android.com/reference/android/content/ContentResolver#query(android.net.Uri,%20java.lang.String[],%20java.lang.String,%20java.lang.String[],%20java.lang.String), you will notice that:
You are trying to pass "group by" stuff into field that formatted as an SQL WHERE clause (excluding the WHERE itself)
There is no such thing as "group by" for the specific query you are using
Your syntax error can easily be fixed but I'm afraid the result will not be what you expect. You should change your query strategy to something else, may be like raw query.

SQLiteQueryBuiler.setProjectionMap() doesn't affect where clause

I have an Android app with a ContentProvider class that queries two tables, users and items.
users table has the following columns:
_id (primary key)
online (integer)
items table has the following columns:
_id (primary key)
user_id (foreign key, maps to users._id)
name (text)
I then have a query that returns the result of the two tables joined together. In my ContentProvider, I use this code to map the column names:
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables("items INNER JOIN users ON users._id=items.user_id");
Map<String, String> columnMap = new HashMap<String, String>();
columnMap.put("item_id", "items._id");
columnMap.put("user_id", "items.user_id");
columnMap.put("user_online", "users.online");
columnMap.put("item_name", "items.name");
queryBuilder.setProjectionMap(columnMap);
However, when I perform the following query, to find all items which are owned by online users:
String[] projection = {"item_name"};
String selection = "user_online=1";
Cursor cursor = getContentResolver().query(uri, projection, selection, null, null);
I get the following exception:
android.database.sqlite.SQLiteException: no such column: user_online (code 1): , while compiling: SELECT items.name FROM items INNER JOIN users ON users._id=items.user_id WHERE (user_online=1)
The problem appears to be that setProjectionMap() affects projection, but not selection.
Is there any other way of solving this problem, short of performing string manipulation on the projection to map the column names manually?
setProjectionMap is needed only because it allows to the output column names of the query.
What you do in the selection is not visible in the resulting cursor, and in any case SQLiteQueryBuilder is not smart enough to parse SQL and replace the correct column names.
Just use the original column names:
String selection = "users.online=1";
To make column aliases available in the selection, create a view for your join:
CREATE VIEW user_items AS
SELECT items._id AS item_id,
items.user_id AS user_id,
users.online AS user_online,
items.name AS item_name
FROM items INNER JOIN users ON users._id=items.user_id;

Out of range error by query more then one images from gallery

When String[] ids has one argument, query return data, when more then one, get error:
Cannot bind argument at index X(number of arguments) because the index is out of range. The statement has 1 parameter.
Cursor cr = ctx.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
"_id = ?",
ids,
orderBy
);
"_id = ?"
This construction serves to reserve place for one parameter. If you want to select items with several ids you better use the folowing:
"_id IN (?,?,?..?)"
Here is the answer about parametrization of this type of query: IN clause and placeholders

Not all contacts returned

I Have tied to get all contacts by using following code
getContentResolver().query(uri, null, null, null, null)
But it doesn't return all contacts. It seems that it returns only that contacts which have in column "single_is_restricted" value "1", but this column cannot be asseccable from aplication, I found it when I was viewing table "contacts" directly through sqlite.
How I can get all contacts?
Thanks.
Check the create statement for the table/view.
For example in ContactManager example you will see this code block;
private Cursor getContacts()
{
// Run query
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
};
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" +
(mShowInvisible ? "0" : "1") + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
If you can get an exception (for example you can change selection...), you can get view/table name from log cat, like this (you can see "ASDF" in log cat, just get an exception);
04-28 12:16:34.682: E/AndroidRuntime(466): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.contactmanager/com.example.android.contactmanager.ContactManager}: android.database.sqlite.SQLiteException: near "'1'": syntax error: , while compiling: SELECT _id, display_name FROM view_contacts_restricted WHERE (in_visible_group =ASDF '1') ORDER BY display_name COLLATE LOCALIZED ASC
Point is; FROM view_contacts_restricted
And now you can check this view's create statement. You can install a root browser app. And copy sqlite file to SDCARD or install sqlite3 to Android Device. then open database from command line;
sqlite3 '/home/semeteycoskun/Desktop/contacts2.db'
Check view;
.schema view_contacts_restricted
Result is;
CREATE VIEW view_contacts_restricted
AS SELECT contacts._id AS _id
, contacts.custom_ringtone AS custom_ringtone
, name_raw_contact.display_name_source AS display_name_source
, name_raw_contact.display_name AS display_name
, name_raw_contact.display_name_alt AS display_name_alt
, name_raw_contact.phonetic_name AS phonetic_name
, name_raw_contact.phonetic_name_style AS phonetic_name_style
, name_raw_contact.sort_key AS sort_key
, name_raw_contact.sort_key_alt AS sort_key_alt
, name_raw_contact.sort_priority AS sort_priority
, name_raw_contact.sort_priority_alt AS sort_priority_alt
, name_raw_contact.sort_locale AS sort_locale
, name_raw_contact.sort_locale_alt AS sort_locale_alt
, name_raw_contact.contact_in_visible_group AS in_visible_group
, has_phone_number, lookup, photo_id
, contacts.last_time_contacted AS last_time_contacted
, contacts.send_to_voicemail AS send_to_voicemail
, contacts.starred AS starred
, contacts.times_contacted AS times_contacted
, status_update_id
, dirty_contact
, has_email
, link_count
, raw_contact_linkpriority1
, link_type1
, raw_contact_linkpriority2
, link_type2
, raw_contact_linkpriority3
, link_type3
, raw_contact_linkpriority4
, link_type4
, raw_contact_linkpriority5
, link_type5
FROM contacts
JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id)
WHERE single_is_restricted=0;
If create statements include single_is_restricted=0 you can not access the rows that single_is_restricted=1.
[sorry for my english]
Some manufacturers like Samsung have deals with Facebook in which Facebook syncs to the device contacts with names, phones, pics, etc. but those contacts can't be accessed via the Contacts APIs.
This is the reason some contacts can't be accessed by your app, but are visible in the stock contacts app.

Categories

Resources