Android : Calculate sum and group by month (SQLite) - java

Is there are any option to select amount, group them by month and calculate sum. I tried to get total sum of each month and pass it to ArrayList.
Example of data:
Amount Date
230 04/03/19
500 05/03/19
400 04/04/19
600 06/04/19
100 04/03/19
... ...
My code structure
private String CREATE_BILLS_TABLE = "CREATE TABLE " + TABLE_BILLS + "("
+ COLUMN_BILL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_BILL_USER_ID + " INTEGER,"
+ COLUMN_DESCRIPTION + " TEXT,"
+ COLUMN_AMOUNT + " INTEGER,"
+ COLUMN_DATE_STRING + " TEXT,"
+ COLUMN_COMPANY_NAME + " TEXT,"
+ COLUMN_CATEGORY + " TEXT,"
+ " FOREIGN KEY ("+COLUMN_BILL_USER_ID+") REFERENCES "+TABLE_USER+"("+COLUMN_USER_ID+"));";
public ArrayList<Bills> getDateByUserID(int userID){
SQLiteDatabase db = this.getReadableDatabase();
// sorting orders
ArrayList<Bills> listBillsDates = new ArrayList<Bills>();
Cursor cursor = db.query(TABLE_BILLS, new String[] { COLUMN_BILL_ID,
COLUMN_BILL_USER_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_DATE_STRING, COLUMN_COMPANY_NAME, COLUMN_CATEGORY}, COLUMN_BILL_USER_ID + "=?",
new String[] { String.valueOf(userID) }, COLUMN_DATE_STRING, null, null, null);
if (cursor.moveToFirst()) {
do {
Bills bills = new Bills();
bills.setAmount(cursor.getInt(cursor.getColumnIndex(COLUMN_AMOUNT)));
bills.setDateString(cursor.getString(cursor.getColumnIndex(COLUMN_DATE_STRING)));
// Adding record to list
listBillsDates.add(bills);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
// return category list
return listBillsDates;
}

I believe that a query based upon :-
SELECT sum(COLUMN_AMOUNT) AS Monthly_Total,substr(COLUMN_DATE_STRING,4) AS Month_and_Year
FROM TABLE_BILLS
WHERE COLUMN_BILL_USER_ID = 1
GROUP BY substr(COLUMN_DATE_STRING,4)
ORDER BY substr(COLUMN_DATE_STRING,7,2)||substr(COLUMN_DATE_STRING,4,2)
;
Note that other columns values would be arbritary results and as such cannot really be relied upon (fine if the data is always the same). Hence they have not been included.
Will produce the results that you want :-
e.g.
Using the following, to test the SQL :-
DROP TABLE IF EXISTS TABLE_BILLS;
CREATE TABLE IF NOT EXISTS TABLE_BILLS (
COLUMN_BILL_ID INTEGER PRIMARY KEY AUTOINCREMENT,
COLUMN_BILL_USER_ID INTEGER,
COLUMN_DESCRIPTION TEXT,
COLUMN_AMOUNT INTEGER,
COLUMN_DATE_STRING TEXT,
COLUMN_COMPANY_NAME TEXT,
COLUMN_CATEGORY TEXT)
;
-- Add the Testing data
INSERT INTO TABLE_BILLS (
COLUMN_BILL_USER_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_DATE_STRING, COLUMN_COMPANY_NAME,COLUMN_CATEGORY)
VALUES
(1,'blah',230,'04/03/19','cmpny','category')
,(1,'blah',500,'05/03/19','cmpny','category')
,(1,'blah',400,'04/04/19','cmpny','category')
,(1,'blah',600,'06/04/19','cmpny','category')
,(1,'blah',100,'04/03/19','cmpny','category')
-- Extra data for another id to check exclusion
,(2,'blah',230,'04/03/19','cmpny','category')
,(2,'blah',500,'05/03/19','cmpny','category')
,(2,'blah',400,'04/04/19','cmpny','category')
,(2,'blah',600,'06/04/19','cmpny','category')
,(2,'blah',100,'04/03/19','cmpny','category')
;
SELECT sum(COLUMN_AMOUNT) AS Monthly_Total,substr(COLUMN_DATE_STRING,4) AS Month_and_Year
FROM TABLE_BILLS
WHERE COLUMN_BILL_USER_ID = 1
GROUP BY substr(COLUMN_DATE_STRING,4)
ORDER BY substr(COLUMN_DATE_STRING,7,2)||substr(COLUMN_DATE_STRING,4,2)
;
Results id :-
The above can then be converted for use by the SQLiteDatabase query method. So your method could be something like :-
public ArrayList<Bills> getDateByUserID(int userID) {
SQLiteDatabase db = this.getReadableDatabase();
String tmpcol_monthly_total = "Monthly_Total";
String tmpcol_month_year = "Month_and_Year";
String[] columns = new String[]{
"sum(" + COLUMN_AMOUNT + ") AS " + tmpcol_monthly_total,
"substr(" + COLUMN_DATE_STRING + ",4) AS " + tmpcol_month_year
};
String whereclause = COLUMN_BILL_USER_ID + "=?";
String[] whereargs = new String[]{String.valueOf(userID)};
String groupbyclause = "substr(" + COLUMN_DATE_STRING + ",4)";
String orderbyclause = "substr(" + COLUMN_DATE_STRING + ",7,2)||substr(" + COLUMN_DATE_STRING + ",4,2)";
ArrayList<Bills> listBillsDates = new ArrayList<Bills>();
Cursor cursor = db.query(TABLE_BILLS, columns, whereclause,
whereargs, groupbyclause, null, orderbyclause, null);
if (cursor.moveToFirst()) {
do {
Bills bills = new Bills();
bills.setAmount(cursor.getInt(cursor.getColumnIndex(tmpcol_monthly_total)));
bills.setDateString(cursor.getString(cursor.getColumnIndex(tmpcol_month_year))); //<<<<<<<<<< NOTE data is MM/YY (otherwise which date to use? considering result will be arbrirtaryy)
// Adding record to list
listBillsDates.add(bills);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
// return category list
return listBillsDates;
}
The above has been tested and run and using the following code :-
ArrayList<Bills> myMonthlyTotals = mDBHelper.getDateByUserID(1);
Log.d("BILLSCOUNT","The number of bills extracted was " + String.valueOf(myMonthlyTotals.size()));
for (Bills b: myMonthlyTotals) {
Log.d("MONTHYLTOTAL","Monthly total for " + b.getDateString() + " was " + String.valueOf(b.getAmount()));
}
In an activity, resulted in the following in the log
:-
04-14 11:58:25.876 16653-16653/? D/BILLSCOUNT: The number of bills extracted was 2
04-14 11:58:25.877 16653-16653/? D/MONTHYLTOTAL: Monthly total for 03/19 was 830
04-14 11:58:25.877 16653-16653/? D/MONTHYLTOTAL: Monthly total for 04/19 was 1000
Please consider the comments in regard to values from non-aggreagted columns be arbitrary values. As per :-
Each non-aggregate expression in the result-set is evaluated once for an arbitrarily selected row of the dataset. The same arbitrarily selected row is used for each non-aggregate expression. Or, if the dataset contains zero rows, then each non-aggregate expression is evaluated against a row consisting entirely of NULL values. SELECT - 3. Generation of the set of result rows.
As per the comments, using recognised date formats can make the underlying SQL simpler and likely more efficient.

Related

How to retrieve Real type data from specific cell in android sqlite?

In this table, I want to retrieve the value 55.2 in a variable.
This value is at row 5 (ID=5) and in the column 'Weight' of type REAL.
I can already get the desired row number which is stored in 'lastID' and I know that my data is in the column 'Weight'. So I have my X and my Y in the table.
I also know the sqlite command to retrieve the 55.2 in my cursor:
Cursor cursor2 = db.rawQuery("SELECT Weight FROM <MYTABLE> WHERE ID=" + lastID, null);
Double lastWeight = cursor2.getDouble(0); //This line is wrong, I need the help here!
But I can't get the 55.2 value I am looking for in my variable lastWeight from cursor2.
Any idea?
Addendum
Here the create table:
String CREATE_TABLE2 = "CREATE TABLE " + <MYTABLE> + " (" + UID2 + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_2 + " TEXT," + COL_3 + " TEXT," + COL_4 + " REAL," + COL_5 + " REAL);";
db.execSQL(CREATE_TABLE2);
After the execution of this line:
Cursor cursor2 = db.rawQuery("SELECT Weight FROM <MYTABLE> WHERE ID=" + lastID, null);
you get the results in cursor2.
A Cursor instance like cursor2 is used to loop through its rows and to do so you must first place its index at the 1st row by moveToFirst():
if (cursor2.moveToFirst()) {
Double lastWeight = cursor2.getDouble(0);
........................................
}
The if statement is necessary just in case the cursor does not contain any rows.

How can I use this query with the query method (SQLiteDatabase.query)?

The task I've been given is to write a query to return the number of orphaned rows. I have achieved this but another task is to then not use the rawQuery method to achieve the same result using the query method.
The issue is that I get java.lang.IllegalStateException: Invalid tables
The tables, there are 3 are
the parent table which has an _id column and a name column
the child table which has an _id column, a name column and a childtoparentlink column that is an integer that links to the parent table.
the friend table which has an _id column, a name column and a friendtochildlink column.
The SQL to create and to put rows into the tables, including some orphans is like
CREATE TABLE parent(_id INTEGER PRIMARY KEY,parentname TEXT);
CREATE TABLE child(_id INTEGER PRIMARY KEY,childname TEXT, childtoparentlink INTEGER);
CREATE TABLE friend(_id INTEGER PRIMARY KEY,friendname TEXT, friendtochildlink INTEGER);
INSERT INTO parent VALUES(null,'Parent A');
INSERT INTO parent VALUES(null,'Parent B');
INSERT INTO child VALUES(null,'Child A',1);
INSERT INTO child VALUES(null,'Child B',2);
INSERT INTO child VALUES(null,'Child X',10); -- orphan
INSERT INTO friend VALUES(null,'Friend A',1);
INSERT INTO friend VALUES(null,'Friend B',2);
INSERT INTO friend VALUES(null,'Friend X',100); -- orphan
The query that works and gives the right values when using rawQuery is
SELECT
(
SELECT count() FROM child
LEFT JOIN parent ON child.childtoparentlink = parent._id
WHERE parent.parentname IS NULL
) AS child_mismatches,
(
SELECT count() FROM friend
LEFT JOIN child ON friend.friendtochildlink = child._id
WHERE child.childname IS NULL
) AS friend_mismatches
I get two columns each with a value of 1 (as wanted).
My actual code is :-
public ArrayList<String> checkLinkIntegrity() {
ArrayList<String> return_value = new ArrayList<>();
String suffix = "_mismatches";
String child_result_cl = TB_CHILD + suffix;
String sq_child_mismatches = "(SELECT count() FROM " +
TB_CHILD +
" LEFT JOIN " + TB_PARENT +
" ON " + TB_CHILD + "." + CL_CHILDTOPARENTLINK + " = " +
TB_PARENT + "." + CL_PARENTID +
" WHERE " + TB_PARENT + "." + CL_PARENTNAME + " IS NULL)" +
" AS " + child_result_cl;
String friend_result_cl = TB_FRIEND + suffix;
String sq_friend_mismatches = "(SELECT count() FROM " +
TB_FRIEND +
" LEFT JOIN " + TB_CHILD +
" ON " + TB_FRIEND + "." + CL_FRIENDTOCHILDLINK + " = " +
TB_CHILD + "." + CL_CHILD_ID +
" WHERE " + TB_CHILD + "." + CL_CHILDNAME + " IS NULL)" +
" AS " + friend_result_cl;
String full_query = "SELECT " + sq_child_mismatches + "," + sq_friend_mismatches;
SQLiteDatabase db = this.getWritableDatabase();
Cursor csr;
Log.d("RAWQUERYSQL",full_query);
csr = db.rawQuery(full_query,null);
return_value.addAll(dumpCursorToStringArrayList(csr,"RAWQUERY"));
// Fails invalid table
csr = db.query(null,new String[]{sq_child_mismatches,sq_friend_mismatches},null,null,null,null,null);
return_value.addAll(dumpCursorToStringArrayList(csr,"SECONDTRY"));
csr.close();
return return_value;
}
and the dumpCursortoStringArrayList method is :-
private ArrayList<String> dumpCursorToStringArrayList(Cursor csr, String tablename) {
ArrayList<String> rv = new ArrayList<>();
int original_position = csr.getPosition();
csr.moveToPosition(-1);
rv.add("Table: " + tablename);
while (csr.moveToNext()) {
rv.add("\tRow # " + String.valueOf(csr.getPosition() + 1));
for (String column: csr.getColumnNames()) {
rv.add("\t\tColumn: " + column + "\tvalue is: \t" + csr.getString(csr.getColumnIndex(column)));
}
}
csr.moveToPosition(original_position);
return rv;
}
I get the same error if I try "" instead of null e.g.
If I use only the rawQuery I get
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS: Table: RAWQUERY
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS: Row # 1
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS: Column: child_mismatches value is: 1
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS: Column: friend_mismatches value is: 1
This is from using
ArrayList<String> results = DBOpenHelper.checkLinkIntegrity();
for (String s : results) {
Log.i("RESULTS",s);
}
How can I run the query with the query method instead of the rawQuery method, to get the better marks?
Your issue is that the query method expects a table as it then generates SQL as per
SELECT your_columns FROM the_table;
As there is no table it issues the Invalid Table exception.
You have to provide something that will satisfy the FROM clause, it cannot be nothing.
You can get around this in a few ways, which I guess is what the homework is trying to get you to ascertain/explore.
Fix 1
You could supply one of the tables that exist e.g. use
csr = db.query(null,new String[]{sq_child_mismatches,sq_friend_mismatches},null,null,null,null,null,"1");
Note the 8th parameter, this LIMITs the number of rows generated to one as there would be a row generated for each row in the fake table.
Fix 2
or as FROM can be a subquery (see diagram) you could use a subquery e.g. one that you have
So you could use :-
csr = db.query(
sq_child_mismatches, //<<<<<<<<<< the fake subquery
new String[]{
sq_child_mismatches,
sq_friend_mismatches
},
null ,null,null,null,null
);
In this case, as the fake subquery returns a single row/result, there is no need for the LIMIT clause.

sqlite fetching data using foreign key: Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters

I am trying to fetch a record from the sqlite database in Android, and having trouble. It often throws java.lang.IllegalArgumentException and gives me the same message.
mListSongs = mSongDao.getSelectedSongs(artist_id);
public List<Song> getSelectedSongs(Long artistId) {
List<Song> listSongs = new ArrayList<Song>();
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
+ DBHelper.TABLE_ARTIST + " a WHERE s."
+ DBHelper.SONG_ID + " = a.'" + DBHelper.ARTIST_ID + "'";
String[] selectionArgs = new String[]{String.valueOf(artistId)};
Cursor cursor;
cursor = mDatabase.rawQuery(selectQuery, selectionArgs);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Song song = cursorToSelectSong(cursor);
listSongs.add(song);
cursor.moveToNext();
}
cursor.close();
return listSongs;
}
private Song cursorToSelectSong(Cursor cursor) {Song song = new Song(); song.setmSong_path(cursor.getString(3)); return song;}
The issue is that you are supplying an argument, as per String[] selectionArgs = new String[]{String.valueOf(artistId)}; and then cursor = mDatabase.rawQuery(selectQuery, selectionArgs); but that the statement (the SELECT statement) has no place-holder (an ?) within it.
So you have 1 argument but the statement has 0 parameters to substitute the argument for.
Changing :-
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
+ DBHelper.TABLE_ARTIST + " a WHERE s."
+ DBHelper.SONG_ID + " = a.'" + DBHelper.ARTIST_ID + "'";
to :-
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
+ DBHelper.TABLE_ARTIST + " a WHERE s."
+ DBHelper.SONG_ID + "=?";
Introduces the parameter and it, the ?, will be substituted for the artist_id passed to the method.
Alternately using :-
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
+ DBHelper.TABLE_ARTIST + " a WHERE s."
+ DBHelper.SONG_ID + " =" + String.valueOf(artist_id);
along with :-
cursor = mDatabase.rawQuery(selectQuery, null);
would also work BUT is open to SQL injection (but not really as it's a long that has been passed, which cannot be a String that could contain dangerous SQL).
i.e. no arguments are passed into rawQuery and therefore there is no expectation that the statement should contain a parameter place-holder (?).
However, there is no need to JOIN the ARTIST table as the SONG table has the ARTIST_ID column.
You'd only need the JOIN if you wanted other details about the ARTIST e.g. artist name (which you probably already know as you've ascertained the ARTIST_ID when invoking the method).
As such the simplified :-
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " WHERE " + DBHelper.SONG_ID + "=?";
would suffice.
Regarding Cursor issues I'd suggest trying :-
cursor = mDatabase.rawQuery(selectQuery, selectionArgs);
DatabaseUtils.dumpCursor(cursor); //<<<<<<<<<< will output the contents of the cursor to the log
while(cursor.moveToNext()) {
String songpath = cursor.getString(cursor.getColumnIndex(DBHelper.SONG_PATH));
Log.d("EXTRACTEDPATH", "Extracted PATH " + songpath); //<<<<<<<<<< output extracted path to the log
Song newsong = new Song();
newsong.setmSong_path(songpath);
listSongs.add(newsong);
}
cursor.close();
return listSongs;
}
Dumps the Cursor immediately after it is retrieved
Uses simpler loop
Uses column name to derive the column offset
outputs the data from the column (if it shows path in log, but you still get empty path in list then it's either setmSong_path that is wrong or how you are getting data from the List.)
I think you want to fetch a list of songs by an artist, providing the artistId.
I believe that in in each row of the songs table DBHelper.TABLE_SONG there is a column for the id of the artist. If there isn't it should be.
Change your sql statement to this:
String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " WHERE " + DBHelper.ARTIST_ID + " = ?";
As I said there must be a column DBHelper.ARTIST_ID or similar to identify the artist of each song.
The ? is the 1 parameter and its value will be artistId.

Cursor returns with no result after SQLite query (passes unit test but fails at run time) -- android

i have this method:
public Note getNoteById(long id) {
Cursor cursor = database.query(Config.NOTES_TABLE, Config.NOTES_COLUMNS, Config.ROW_ID+"="+id, null, null, null, Config.ROW_ID + " DESC");
//no match found
if(cursor.getCount() == 0)
return null;
cursor.moveToFirst();
Note result = new Note();
result.setId(cursor.getLong(cursor.getColumnIndex(Config.ROW_ID)));
result.setTitle(cursor.getString(cursor.getColumnIndex(Config.TITLE)));
result.setText(cursor.getString(cursor.getColumnIndex(Config.TEXT)));
result.setViewOrder(cursor.getLong(cursor.getColumnIndex(Config.VIEW_ORDER)));
result.setCreated(cursor.getString(cursor.getColumnIndex(Config.CREATED)));
result.createTagsFromString(cursor.getString(cursor.getColumnIndex(Config.TAGS)));
return result;
}
My problem is in the first few lines. The cursor at the beginning always returns with a count of 0 therefore making the function always returns null -- ONLY AT RUNTIME! -- i have written a test case for this method and it passes so i cant figure out why it would only fail at runtime?
heres the relevant part of the test case. i basically insert new data to the table and try to get it back by its id and compare attributes to confirm its the same:
#Test
public void testGetNoteByIdMatch(){
testTable.load();
Assert.assertEquals(0, testTable.getAllNotes().getCount());
testTable.newEntry(note1);
testTable.newEntry(note2);
Cursor cursor = testTable.getAllNotes();
Assert.assertEquals(2, testTable.getAllNotes().getCount());
cursor.moveToFirst();
Note result = new Note();
result.setId(cursor.getLong(cursor.getColumnIndex(Config.ROW_ID)));
result.setTitle(cursor.getString(cursor.getColumnIndex(Config.TITLE)));
result.setText(cursor.getString(cursor.getColumnIndex(Config.TEXT)));
Note checker = testTable.getNoteById(result.getId());
Assert.assertEquals(result.getId(), checker.getId());
Assert.assertEquals(result.getTitle(), checker.getTitle());
//move and try another search
cursor.moveToNext();
result = new Note();
result.setId(cursor.getLong(cursor.getColumnIndex(Config.ROW_ID)));
result.setTitle(cursor.getString(cursor.getColumnIndex(Config.TITLE)));
result.setText(cursor.getString(cursor.getColumnIndex(Config.TEXT)));
checker = testTable.getNoteById(result.getId());
Assert.assertEquals(result.getId(), checker.getId());
Assert.assertEquals(result.getTitle(), checker.getTitle());
}
this is the table structure in the onCreate method for the database:
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + Config.NOTES_TABLE + " (" +
Config.ROW_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
Config.TITLE + " TEXT NOT NULL, " +
Config.TEXT + " TEXT NOT NULL, " +
Config.CREATED + " TEXT NOT NULL, " +
Config.VIEW_ORDER + " INTEGER NOT NULL, " +
Config.TAGS + " TEXT NOT NULL)"
);
}
Your test checks that the values can be read out in the same order they were inserted, but does not actually verify the data is going in as expected. It's possible that the result and checker objects both have null values for all properties. Verify that the object properties have the expected values once read out of the db.

Getting Contacts based on the GroupID in Android

I'm having kind of a problem here, since I just startet developing for Android. I downloaded the sample from the official Android website "http://developer.android.com/training/contacts-provider/retrieve-names.html", which is basically capable of retrieving an showing all the contacts from the phone. The feature I wanted to add is to just show contacts from a certain group like "Friends" (hardcoded).
As far as I narrowed it down I have to change the selection part
final static String SELECTION =
(Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME) +
"<>''" + " AND " + Contacts.IN_VISIBLE_GROUP + "=1";
to something like this
final static String SELECTION =
Contacts.GroupID = "Friends";
which gives me errors, because it can't find the column.
I'm very eager to explore the potential of Android, but that one is giving me headache.
There two ways for getting list of contacts of a group. First, I suppose you have GroupId and want to get related list of contacts.
String[] projection = {
ContactsContract.Groups._ID,
ContactsContract.Groups.TITLE,
ContactsContract.Groups.ACCOUNT_NAME,
ContactsContract.Groups.ACCOUNT_TYPE
};
return context.getContentResolver().query(
ContactsContract.Groups.CONTENT_URI, projection, ContactsContract.Groups._ID + "=" + groupId , null, null
);
Second way:
I suppose you want to get contacts of specific group by a constants name. so, it's enough you change above codes:
context.getContentResolver().query(
ContactsContract.Groups.CONTENT_URI, projection, ContactsContract.Groups.ACCOUNT_NAME + "='Friends'" , null, null
);
Now you have necessary details from specific Group. Then you can fetch list of Contact List:
public static Cursor getContactsOfGroup(Group group) {
// getting ids of contacts that are in this specific group
String where = ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID + "="
+ group.id + " AND "
+ ContactsContract.CommonDataKinds.GroupMembership.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE + "'";
Cursor query = context.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[] {
ContactsContract.CommonDataKinds.GroupMembership.CONTACT_ID
}, where, null, ContactsContract.Data.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
String ids = "";
for (query.moveToFirst(); !query.isAfterLast(); query.moveToNext()) {
ids += "," + query.getString(0);
}
if (ids.length() > 0) {
ids = ids.substring(1);
}
// getting all of information of contacts. it fetches all of number from every one
String[] projection = new String[]{
"_id",
"contact_id",
"lookup",
"display_name",
"data1",
"photo_id",
"data2", // number type: 1:home, 2:mobile, 3: work, else : other
};
String selection = "mimetype ='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'"
+ " AND account_name='" + group.accountName + "' AND account_type='" + group.accountType + "'"
+ " AND contact_id in (" + ids + ")";
return context.getContentResolver().query(BASE_URI, projection, selection, null, null);
}
Notice, in second fetch in this method we check accountName and accountType to be sure this record is related this group, because may be there are some records that stored for another Apps like WhatsApp. and we don't like get those. ok?
I hope will useful for you.

Categories