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.
Related
I am having trouble with altering the search parameters within SQLite, currently, the search functions that I have for searching film titles and genres can only return the specific result, e.g., Action will only bring back Action films and not Action, Adventure films.
I have had a friend manage to have it work within the SQLite Studio itself, but using this method has been unsuccessful. He suggested using the following ORDER BY, however, it still gives the same results.
Cursor c = sqdb.rawQuery("SELECT * FROM filmography WHERE genre LIKE '%" + searchGenre + "' ORDER BY LENGTH(genre) ASC",
null);
I am at a loss now as I cannot seem to come across or figure out the answer. How would I go about changing the SQL so that if you were to search say "Action" in the genre search, it would bring back all results so eg., "Film 1 = Action, Film 2 = Action, Adventure, Film 3 = Action, Crime" and so on?
Example of genre data: "Capone, Biography, Crime, Drama, Fonse, 2020, 4.7/10
Black Hawk Down, Drama, History, War, Twombly, 2001, 7.7/10
Venom, Action, Adventure, Sci-Fi, Eddie Brock / Venom, 2018, 6.7/10
public String searchByTitleInFilmography(SQLiteDatabase sqdb, String searchfilmTitle)
{
String result = "";
Cursor c = sqdb.rawQuery("SELECT * FROM filmography WHERE filmTitle = '" + searchfilmTitle + "'",
null);
if (c != null)
{
if (c.moveToFirst())
{
do
{
String id = c.getString(0);
result = result + id + ": ";
String filmtitle = c.getString(1);
result = result + "Title: " + filmtitle + ". ";
String genre = c.getString(2);
result = result + "Genre(s): " + genre + ". ";
String role = c.getString(3);
result = result + "Role: " + role + ". ";
String year = c.getString(4);
result = result + "Released: " + year + ". ";
String imdbrating = c.getString(5);
result = result + "Rating: " + imdbrating + "\n" + "\n";
Log.w("FILM_TITLE_GENRE", "ID - " + id +":" + " Genre(s) = " + genre);
} while (c.moveToNext());
}
else
{
result = "No Films Found With The Title = " + searchfilmTitle;
}
}
c.close();
return result;
} // public String serachByTitleInFilmography(SQLiteDatabase sqdb, String searchTitle)
If the column genre contains values like a comma separated list of genres, then you should change the operand of the operator LIKE like this:
String sql = "SELECT * FROM filmography WHERE ',' || REPLACE(genre, ', ', ',') || ',' LIKE '%,' || ? || ',%'"
Cursor c = sqdb.rawQuery(sql, new String[] {searchGenre});
REPLACE() removes all spaces after each comma and each value of genre becomes like: ',Action,Crime,Drama,'.
When you pass 'Action' as the parameter for the ? placeholder then the sql statement becomes:
SELECT * FROM filmography WHERE ',Action,Crime,Drama,' LIKE '%,Action,%'
which is what you want: all the rows that contain 'Action' anywhere in the column genre.
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.
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.
I have two tables; a 'parent' and a 'child' table. (not SQLite defitinions, just something i call them)
Everytime a child-object is created, it is assigned the value 0 in one of its columns.
When a new parent-object is created, every unassigned child-object, has to update the value mentioned before, to the parent-object's ID. My code looks like this:
public long createWorkout(String workoutName){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, workoutName);
//Creates a new parent-object (a workout - the childs are exercises)
//the generated ID is returned as a long (workout_pk_id)
long workout_pk_id = db.insert(TABLE_WORKOUT, null, values);
//Selects all objects in the child-table with KEY_WORKOUT_ID = 0 (the column mentioned before)
String selectQuery = "SELECT * FROM " + TABLE_EXERCISE + " WHERE " + KEY_WORKOUT_ID + " == " + 0;
Cursor cursor = db.rawQuery(selectQuery, null);
//Takes each found object with value 0, and updates the value to the returned parent-ID from before.
if (cursor.moveToFirst()) {
do {
String k = "UPDATE " + TABLE_EXERCISE + " SET " + KEY_WORKOUT_ID + " == " + workout_pk_id;
db.execSQL(k);
} while (cursor.moveToNext());
}
return workout_pk_id;
}
But for some reason this doesn't work. The ID the childs/exercises remains 0. Can you help me?
I don't know if the error is somewhere in the setup of my tables, in that case i could provide some more information.
Thanks in advance. /Jeppe
EDIT: This is used in android, and I have debugged and verified that the workout_pk_id is returned, 45 objects are found in the selectQuery and yet it doesn't work. I also tried ContentValues to update the values, didn't work.
Edited the " == " to " = ", but the value is still not updated.
This is from eclipse - I've created a workout called "test", with the ID 160.
The exercise "test1" has the ID 430 (unique) but the workout_id is still 0.
It's been awhile since I did any Android stuff but I believe the "==" operator is incorrect:
String k = "UPDATE " + TABLE_EXERCISE + " SET " + KEY_WORKOUT_ID + " == " + workout_pk_id;
The operator you're using is a comparative operator, "=" is the assignment operator.
I also believe there is a better way to do what you are trying to do, currently refreshing my memory on Android so I'll get back to you. In the meantime tell me if replacing the operator works
Yeah so another way you can do this is by using subqueries. So it would look something like:
UPDATE TABLE_EXCERCISE SET KEY_WORKOUT_ID = WORKOUT_PK_ID WHERE KEY_WORKOUT_ID =
(
*subquery here to select parent object ids*
)
Here's a link to help:
http://www.tutorialspoint.com/sqlite/sqlite_sub_queries.htm
Let me know how this works for you.
I think you have to look to your update query.
It has to be:
String k = "UPDATE " + TABLE_EXERCISE + " SET " + KEY_WORKOUT_ID + " = " + workout_pk_id;
Look at the "=" between KEY_WORKOUT_ID and workout_pk_id.
I currently I have my database set up like the following:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_LOCKERNUMBER
+ " TEXT NOT NULL, " + KEY_STATUS + " INTEGER, " + KEY_PIN
+ " INTEGER);");
And I am trying to write a method to get the pin code from the column for a specific locker number. Any ideas? I am very new I would like think I would need to use the query function and a cursor. I just one to get the integer value and store it into an int variable so I can compare the pin codes from what the user types in to the one in the database.
Queries to database returns in a Cursor object. You should use the db.query() method to get a row(s). Pass the table name, an array of columns you want to get (or null if you want all of them), pass a selection string that should be like "id = ?" or "key > ?", etc, then pass a String array containing the value for those ? inside the previous string,
and finally pass null for having, groupBy and orderBy unless you want to use them.
Cursor cursor = db.query(TABLE_NAME, new String[] { KEY_ROWID }, "id = ?", new String[] { Integer.toString(id) }, null, null, null);
After you get the Cursor, do cursor.moveToFirst() or cursor.moveToPosition(0) (can't remember the exact method, but the point is to move the cursor to the first retrieved row)
then you're going to iterate through the cursor with
while(cursor.moveToNext()) {
int keyRowIdColumnIndex = cursor.getColumnIndex(KEY_ROWID);
int yourValue = cursor.getInt(keyRowIdColumnIndex);
int keyLockNumberColumnIndex = cursor.getColumnIndex(KEY_LOCKNUMBER);
int pin = cursor.getInt(keyLockNumberColumnIndex);
}
This is a pretty straight forward task and there is a bunch of tutorials, examples, similar questions on SO:
How to perform an SQLite query within an Android application?
In general - you need to query the database passing your search arguments. See the documentation.
It will return you a Cursor with the matching results, which you can then iterate over and manipulate as you wish.
Fyi - storing password in a database table is a bad idea. On Android databases can be accessed and easily read. You either need to encrypt your data or think of another way to store it if it's important.
//Try This code
public String getLabeId(String LockNo)
{
ArrayList<String> Key_Pin_array = new ArrayList<String>();
Cursor cur = db.rawQuery("SELECT * FROM DATABASE_TABLE where KEY_LOCKERNUMBER = '" + LockNo + "'", null);
try {
while (cur.moveToNext())
{
System.out.println("Key_Pin" + cur.getString(3));
Key_Pin_array.add(cur.getString(3));
}
}
catch (Exception e)
{
System.out.println("error in getLabelID in DB() :" + e);
}
finally
{
cur.close();
}
return id;
}