Search in Android calendar Instances - android

I want to search events in Android Calendar API Instances table by title or description. But I can't fetch all instances from the table because of API. CalendarContract.Instances has CONTENT_SEARCH_URI. Does anybody know how to use it?

Here is what is CONTENT_SEARCH_URI and how to use it.
CONTENT_SEARCH_URI = content://com.android.calendar/instances/search
If you want to use it, add 3 arguments: begin in millis, end in millis and search as String.
Uri.Builder builder = CalendarContract.Instances.CONTENT_SEARCH_URI.buildUpon();
builder.appendPath(Long.toString(startDate));
builder.appendPath(Long.toString(endDate));
builder.appendPath(searchString);
Uri uri = builder.build();
The path will be content://com.android.calendar/instances/search/[your begin]/[your end]/[your search]
If you make query with this Uri, Android makes this SQL:
SELECT Instances._id AS _id, Instances.event_id AS event_id,
title, description, eventLocation
FROM (Instances INNER JOIN view_events AS Events ON
(Instances.event_id=Events._id))
LEFT OUTER JOIN Attendees ON (Attendees.event_id=Events._id)
WHERE (begin<=? AND end>=?)
GROUP BY Instances._id
HAVING (title LIKE ? ESCAPE "#"
OR description LIKE ? ESCAPE "#"
OR eventLocation LIKE ? ESCAPE "#"
OR group_concat(attendeeEmail) LIKE ? ESCAPE "#"
OR group_concat(attendeeName) LIKE ? ESCAPE "#" )

Related

Query that brings all the parents whose children meet a certain criteria

I need a query that brings all the parents whose children meet a certain criteria.
So far this is giving me something different than expected:
#Transaction
#Query("SELECT * FROM piece_unit_table put WHERE (SELECT et.date_of_creation FROM expense_table et WHERE et.piece_unit_parent_id = put.piece_unit_id) = :dateOfExpenseCreation AND project_id = :projectId")
public abstract LiveData<List<PieceUnit>> getPieceUnitsWhereDateOfExpenseCreation(long dateOfExpenseCreation, int projectId);
A more readable version of the same code above:
SELECT *
FROM piece_unit_table put
WHERE (
SELECT et.date_of_creation
FROM expense_table et
WHERE et.piece_unit_parent_id = put.piece_unit_id
) = :dateOfExpenseCreation
AND project_id = :projectId
At first I thought I got a jackpot with that one because it gave me responses on the first try (I usually spend a whole day just thinking about the structure of the query, I hate them), I never gave it too much thought, but the days passed by and it stopped giving me responses, so I'm guessing that maybe, the query was comparing some other dates inside the WHERE clause, more precisely, the dates on which the pieces where created.
Now that I reread it again it looks like a pretty bad query...
The way in which I'm storing dates (from the children side):
public void insertExpense(Expense expense) {
long now = Converters.dateToTimestamp(LocalDate.now());
expense .setDate_of_creation(now);
long edited = System.currentTimeMillis();
expense .setLast_edited(edited);
Log.println(Log.WARN, TAG, "insertExpense: date of creation is: " + expense.getDate_of_creation());
Log.println(Log.WARN, TAG, "insertExpense: expense project is: " + expense.getParent_project_id());
Log.println(Log.WARN, TAG, "insertExpense: expense piece parent is: " + expense.getPiece_unit_parent_id());
insert(expense);
}
The observer side:
Log.println(Log.ERROR, TAG, "getPieceUnitGroupedByExpenseProductsAtDateAndProject: specific date is: " + specificDate);
Log.d(TAG, "getPieceUnitGroupedByExpenseProductsAtDateAndProject: project id is: " + project);
MyObserver
.observeOnce(
pieceUnitRepository.getPieceUnitsWhereDateOfExpenseCreation(
specificDate,
project
),
pieceUnits ->
{
Log.d(TAG, "getPieceUnitGroupedByExpenseProductsAtDateAndProject: piece units are: " + pieceUnits);
if (pieceUnits != null && pieceUnits.size() > 0) {
PieceUnit p = pieceUnits.get(0);
Log.println(Log.WARN, TAG, "getPieceUnitGroupedByExpenseProductsAtDateAndProject: Hello there ;) : " + p.getBeginning_date());
}
The Logd's:
insertExpense: date of creation is: 18469
insertExpense: expense project is: 1
insertExpense: expense piece parent is: 4
getPieceUnitGroupedByExpenseProductsAtDateAndProject: specific date is: 18469
getPieceUnitGroupedByExpenseProductsAtDateAndProject: project id is: 1
getPieceUnitGroupedByExpenseProductsAtDateAndProject: piece units are: []
I'm not asking for a full solution, but any input could point me in the right direction, so thanks in advance.
Final answer (from second update):
SELECT
put.*
FROM piece_unit_table put
WHERE
EXISTS(
SELECT
1
FROM
expense_table et
WHERE
et.date_of_creation = :dateOfExpenseCreation AND et.piece_unit_parent_id = piece_unit_id
) AND
put.project_id = :projectId
EDITS
First answer :
In SQL there seems to be a function that helps on these cases:
all or not exist
https://stackoverflow.com/a/42439405/11214643
In the SQLite case there doesn't seem to be a direct equivalence, and every solution seems to be a case by case workaround depending on the type of clause.
In my case I LEFT JOIN-ed the children table, but group by-ing it before the join to avoid repeated rows on the left table.
As is expected, it was during the child table sub-query, that I filtered the table by their date condition
SELECT put.*
FROM piece_unit_table put
LEFT JOIN(
SELECT
piece_unit_parent_id
FROM
expense_table et
WHERE
et.date_of_creation = :dateOfExpenseCreation
GROUP BY
et.piece_unit_parent_id
) et1
ON
et1.piece_unit_parent_id = put.piece_unit_id
WHERE
put.project_id = :projectId
UPDATE:
It seems that behind curtains(either be SQLite or the ROOM interface), the LEFT JOIN is happening before the sub-query executes its own WHERE clause, as a result, the query is giving me parents, even when there are no children that meet the criteria, so the solution was to bring an additional column from the child temp table to the 'front', and check for it's non null-ability.
SELECT
put.*,
et1.puId AS expPuId
FROM piece_unit_table put
LEFT JOIN(
SELECT
piece_unit_parent_id AS puId
FROM
expense_table et
WHERE
et.date_of_creation = :dateOfExpenseCreation
GROUP BY
et.piece_unit_parent_id
) et1
ON
et1.puId = put.piece_unit_id
WHERE
put.project_id = :projectId AND expPuId NOT NULL
UPDATE 2:
Thanks to #forpas
The EXISTS and NOT EXISTS operators are in fact supported by SQLite, also, what was bringing me parents even when no children met the criteria was the second WHERE clause that was applied directly to the left table, but even if there was no clause applied to this table, it would've still gave me answers, because that's how LEFT JOIN works, if there are no matches it fills them with NULL's.
Here is a query that has the expected result, but does it better.
SELECT
put.*
FROM piece_unit_table put
WHERE
EXISTS(
SELECT
1
FROM
expense_table et
WHERE
et.date_of_creation = :dateOfExpenseCreation AND et.piece_unit_parent_id = piece_unit_id
) AND
put.project_id = :projectId

Sorting Query for SQL

How can we achieve the following sorting order using a query in SQL?
Title_a
Title_b
Title_c
Title_d
Title_1a
Title_1b
Title_1c
Title_1d
Title_11a
Title_11b
Title_11c
Title_111a
Title_111b
Title_111c
Title_111d
Title_1111a
Title_1112a
Title_1112b
Title_12a
Title_12b
Title_12c
Title_1311a
Title_1311b
Title_1311c
Title_1311d
I have tried String sort="CAST ("+ "title" + " AS INTEGER)";
but the results are not satisfying
For those strings it would order fine if it weren't for that last character.
So for those strings you could order by what's before the last character, then the last character.
select *
from yourtable
order by substr(title,1,length(title)-1), substr(title,length(title),1)
Expanding on my comment, "Title_1311b" the value 1311 is added to the ASCII value of "b".
Declare #col varchar(15) = 'Title_1311b'
SELECT SUBSTRING(#col, PATINDEX('%[0-9]%', #col), PATINDEX('%[0-9][^0-9]%', #col) - PATINDEX('%[0-9]%', #col) + 1) + ascii(right(#col,1))+1
Can you add this to your sql query and see what happens?
ORDER BY SUBSTRING(#col, PATINDEX('%[0-9]%', #col), PATINDEX('%[0-9][^0-9]%', #col) - PATINDEX('%[0-9]%', #col) + 1) + ascii(right(#col,1))+1

String with \n in single string android

I have multiple value in single string, but I want to send in every string value on new line. I have written the following code, but it's not working.
String text ="Address" + strpropertyAddress +"\n"+ "Price" + strPrice;
This is my service method where i pass the string.
sendPropertyApi(text, sendto);
I have checked every where, and it is exactly same. Basically the string data should be sent in on a new line, but it's sent in on a single line.
Assuming(Because of Android tag) you are setting this text in textView or editText, for that I think you have to escape \. So use \\n instead. Try following:
String text ="Address" + strpropertyAddress +"\\n"+ "Price" + strPrice;
Or it is always better to use default line separator like following:
String text ="Address" + strpropertyAddress +System.getProperty("line.separator")+ "Price" + strPrice;

String to display number currency in Android

I have a string
String retail = c.getString(c.getColumnIndex("retail"));
The date is being passed as "99999", I need it to print out as "999.99", how can I do this?
If you always have to add the "." 2 character before the end, this should work:
retail = retail.substring(0, retail.length()-2) + "." + retail.substring(retail.length()-2,retail.length());
This will add a dot two character before the end of the String, as you need.

understanding the use of ContentUris.appendId to query the calendar provider

The code i'm working on lists the events from the calendar, i need to limit the range of dates, and in the examples i see this code:
// Construct the query with the desired date range.
Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startMillis);
ContentUris.appendId(builder, endMillis);
I don't understand why appendId is used in this way. startMillis and endMillis are not ids, i would expect that the parameter name had to be provided eg "startdate" , It's not clear to me why this works, and what other parameters could be specified this way. Are there more parameters supported by appenedId? How can i know?
What appendId actually does is add a /# to your uri where # is a number. In your example (assuming startMillis = 1000 and endMillis = 3000 and the uri content://com.google.calendar/) this would mean your uri could end up like this:
content://com.google.calendar/1000/3000
This is something that a uri parser can pickup:
URIMatcher.addURI(AUTHORITY, calendar + "/#/#", DATE_RANGE);
Long story short: appendId is just a convenient and type-safe way to add an integer to your uri path.
I too have been trying to understand more about ContentUris as I had a section of code that wasn't working within the CalendarContract Instances table. This is strange because I didn't need to pass these in for the Calendars or Events table queries that I have developed.
So I added the appendId statements and passed in the current time in UTC for both values and the code now works. The actual query in my code is using the current time to looking for current events - please see the code below. If I take the appendID statements out an exception is raised - I think it was something like Content Provider URL not found.
String instanceQuery = "EVENT_ID = " + event_id +
" AND begin <= " + now +
" AND end >= " + now;
Uri.Builder eventsUriBuilder = CalendarContract.Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(eventsUriBuilder, now);
ContentUris.appendId(eventsUriBuilder, now);
Uri eventsUri = eventsUriBuilder.build();
Cursor instanceCursor = null;
instanceCursor = ctx.getContentResolver().query(eventsUri,
new String[] { CalendarContract.Instances.EVENT_ID,
CalendarContract.Instances.BEGIN,
CalendarContract.Instances.END},
instanceQuery,
null,
null);
My code is working but I would like to know what impact the appendID statements actually have, e.g. do the values add any constraints. It looks like my actual query is overriding any implied range that is passed in and I really don't understand why they are required.
Hopefully a brief explanation from someone who understands this more would benefit the developer community....

Categories

Resources