Using ContactsContract, query matching name or email - android

Is it possible to do one query to ContactsContract to get a set of contacts which match either the display name or a phone number or an email address?
This is essentially a join of the Contacts and Data "tables" (in quotes because they only look like tables through the interface but may not be).
In other words, I'd like a where clause something like (simplifying the syntax a bit)
where Contacts.DISPLAY_NAME like "%?%"
or (Data.MIMETYPE = Phone.CONTENT_ITEMTYPE
and CommonDataKinds.Phone.NUMBER like "%?%")
or (Data.MIMETYPE = Email.CONTENT_ITEMTYPE
and CommonDAtaKinds.Email.ADDRESS like "%?%")
and the tables are joined like
Data.RAW_CONTACT_ID = RawContacts.ID and RawContacts.CONTACT_ID = Contacts.ID
I could do this as separate queries without the join, but then ordering the results becomes difficult. I'd like them ordered by display name.

If you only want to match name/email/phone then you can do:
WHERE Data.MIMETYPE IN (StructuredName.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE)
AND Data.DATA1 LIKE "%?%"
If you're ok with extending the possible match fields, then you can simplify the query to:
WHERE Data.DATA1 LIKE "%?%"
This will match CommonDataKinds.StructuredName.DISPLAY_NAME, CommonDataKinds.Email.ADDRESS, CommonDataKinds.Phone.NUMBER, and more.

The answer was stairing me in the face.
The Data table is already a join (or looks like one, maybe it is a denormalized table internally). Thus, all I need to do is query for all three matches directly:
where Data.DISPLAY_NAME like "%?%"
or (Data.MIMETYPE = Phone.CONTENT_ITEMTYPE
and CommonDataKinds.Phone.NUMBER like "%?%")
or (Data.MIMETYPE = Email.CONTENT_ITEMTYPE
and CommonDAtaKinds.Email.ADDRESS like "%?%")
Note the Data.DISPLAY_NAME, above.

Related

Android Room inner join returns columns which are not used

I have a table for orders and customers. Customers contains an order ID and email. I wish to search for orders by customer email.
This is what I have come up with:
#RewriteQueriesToDropUnusedColumns
#Query(
"SELECT * FROM orders INNER JOIN order_customers ON order_customers.order_id = orders.id " +
"WHERE (order_customers.email LIKE '%' || :email || '%') ORDER BY orders.collection_time DESC"
)
protected abstract fun loadByEmail(email: String): LiveData<List<Order>>
I get a cursor mismatch warning "the query returns some columns which are not used" that I am loading all of the customer columns, when really all I want is orders. Adding the suggested #RewriteQueriesToDropUnusedColumns does not do anything. So what is the best syntax here? Should I just be embedding customers into the order DAO, or is there a simple solution without remodeling and migrating the data?
I can see that instead of saying SELECT * I can individually specify every order column but that is supposed to be the whole reason for Room...
You can use SELECT orders.* FROM orders INNER JOIN ....
Adding the suggested #RewriteQueriesToDropUnusedColumns does not do anything.
This could be because of the caveat:-
Note that Room will not rewrite the query if it has multiple columns that have the same name as it does not yet have a way to distinguish which one is necessary.
I'd suggest always using unique column names, doing so can avoid issues with ambiguities
Note that it appears that when there are duplicate column names, then the value of last column with the duplicated name is used by room. As can be seen in this example

Accent insensitive query in the contacts provider

I want to make a contacts query where the selection is in the form Phone.DISPLAY_NAME_PRIMARY + " LIKE ?, but I want the search to be accent insensitive.
If I use COLLATE LOCALIZED, it works with the = operator, not with the like.
Android's default contact app somehow manages to do that.
Instead of making a query to ContactsContract.Data.CONTENT_URI and using a "selection", make a query to ContactsContract.Contacts.CONTENT_FILTER_URI where the query is added as an additional path segment.

How to Perform the following query using Greendao ?

I have 2 tables A and B.
Table A contains names and table B contains selected names.
Now I would like to perform the following query on these tables using greendao, Please let me know if it is possible and if it is not are there any alternatives (maybe a raw query).
select *
from A inner join B
on A.nameid = B.nameid
Also, Table A columns: id, nameid, name
and Table B columns: id, nameid, name, rating
I think this might help.
You can use the raw query as a fake join. And you get all you want in the Query object
Query query = ATableDao.queryBuilder().where(
new StringCondition("nameid IN " +
"(SELECT nameid FROM B_Table )").build();
Since "nameid" doesn't seems to be a unique identifier in your sample. I won't suggest to use Relations to solve this issue. If you are try to use Relations, you can find my previous answer here.
Try this:
List<ATableObj> listATableObj = ATableDao.queryRawCreate(", BTable BT
WHERE BT.nameid = T.nameid").list();
If you use greendao this works differntly:
Instead of your query you select rows from table a (or b) and if you need a field of b (or a) you call getB() (or getA()) to get the corresponding row of that table.
If you have rows in table a that have no match in table b and you have rows in table b that have no match in a and you onlly want to select everything that has matches uin both tables, you would have to do a raw query to filter the rows of a (or b).

How can I return a record based on only a partial match of that record?

I've done quite a bit of research on what I thought would be an easy question but I cannot find what I am looking for. I am simply trying to return a record as a match with only a search term matching part of the text in the record.
For example, if the user searches for "ed" I would like any record that contains "ed" to be returned. So if there was a record with the name "Edward" in the name column it would be returned as a match. If there was a record with "finished" in the description, it would also return that record as a match.
I have looked into full text search but not sure if this is something that I would need to do or if it would even do what I need.
As always, I'm not looking for an answer per say, I'm just looking for a direction.
Never used SQLite before, but does it have the "LIKE" operator?
In MySQL, you can do something like:
SELECT name FROM list WHERE name LIKE '%ed%';
Here is some code that will do what you want if you are querying a content provider. If you are querying a sqlite database object directly, the parameters are similar but different.
String search = "ed";
// surround it with the SQL wildcard '%'
String q = "%" + search + "%"
Cursor c = getContentResolver().query(uri,
new String[] { column1, column2 },
"column_name like ?",
new String[] { q },
null);
The snippet will search the content provider at uri for the string ed in column_name.

Is it possible have something like the GROUP BY clause in an Android managedQuery?

I'm planning to support Android devices from 2.0 onwards so I am using a managedQuery to query contacts. I get multiple results for people with the same name and phone number so I would like those results to be grouped. (That is I want each name and phone number combination to be unique)
IS it possicle to group these results in a managed query (similar to the GROUP BY clause in SQL)
Mel
You can use a hack in the selection statement like "1) GROUP BY (" + Phone.DISPLAY_NAME;.

Categories

Resources