Sorting Query for SQL - android

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

Related

Room/SQLite returning two different results in one query

So I've got the following queries:
//returns min max value my odomoter field must have
#Query("SELECT MAX(odometer) FROM MaintenanceRecord WHERE vehicleId = :maintenanceVehicleId AND " +
"maintenanceTs < :dateAsLong")
Maybe<Float> getMinAllowedOdometer(long dateAsLong, int maintenanceVehicleId);
//returns the max value my odometer field is allowed to have
#Query("SELECT MIN(odometer) FROM MaintenanceRecord WHERE vehicleId = :maintenanceVehicleId AND " +
"CAST(strftime('%s',DATE(maintenanceTs/1000,'unixepoch')) AS integer) > " +
"CAST(strftime('%s',DATE(:dateAsLong/1000,'unixepoch')) AS integer)")
Maybe<Float> getMaxAllowedOdometer(long dateAsLong,int maintenanceVehicleId);
One function returns the min value the odometer column must have, and the other query returns the max value the odometer column is allowed to have.
The issue is that BOTH functions are executed after each other since I need to subscribe to both functions. That's bad practice, In my honest opinion.
Can I put these two queries in one query and return Maybe<Float, Float> as a result?
My other solution would be running these functions synchronously; instead of Maybe<Float>, I would directly return Float.
You can use conditional aggregation to get both columns in a single query:
SELECT MAX(CASE WHEN maintenanceTs < :dateAsLong THEN odometer END) AS max_odometer,
MIN(CASE WHEN CAST(strftime('%s', DATE(maintenanceTs / 1000, 'unixepoch')) AS INTEGER) > CAST(strftime('%s', DATE(:dateAsLong / 1000,'unixepoch')) AS INTEGER) THEN odometer END) AS min_odometer
FROM MaintenanceRecord
WHERE vehicleId = :maintenanceVehicleId;

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

Search in Android calendar Instances

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 "#" )

Ormlite Join 3 Tables (Many-to-Many)

I'm trying to create search interface via ORMLite in Android. There are 3 tables created, that are making many-to-many relationship. (Recipe >> RecipesForTag << Tag)
tagQueryBuilder.where()
.like(Tag.COLUMN_NAME, "%" + text + "%");
recipesForTagQueryBuilder
.joinOr(tagQueryBuilder);
recipeQueryBuilder
.joinOr(recipesForTagQueryBuilder)
...other joins
.where()
.like(Recipe.COLUMN_TITLE, "%" + text + "%");
PreparedQuery<Recipe> preparedQuery = recipeQueryBuilder.prepare();
return recipeDao.query(preparedQuery);
When I'm not using line with .joinOr(recipesForTagQueryBuilder) everything is working fine. So what am I doing wrong?
OK my bad.
The only thing that was bad was using joinOr while I needed leftJoinOr... The question has one main problem: when middle table is empty no result will be find (also when ...other joins is nonempty). So result is simple:
recipesForTagQueryBuilder
.leftJoinOr(tagQueryBuilder);
recipeQueryBuilder
.leftJoinOr(recipesForTagQueryBuilder)

Read string from sign to sign from string

I'm trying to find a way to read some specified part from input string. I have a incoming input ( only integers ) where I have special signs for separate a data . It's looks like : < data1 >,< data2 >,< data3 >.
My question is how to do a proper solution for reading it to separate variables?
String[] separated = DataString.split(",");
separated[0]; // this will contain data1
separated[1]; // this will contain data2
EDIT :-
I need to read data between " < " and " > " . so how should I do it ?
Well, After the inital split as show above you can go with substring with startindex of "<" and endindex of ">"
separated[0] = strData.substring((separated[0].indexOf("<") + 1), separated[0].indexOf(">"));
hope this helps...
String#split is what you are looking for
StringTokenizer is the easiest solution!

Categories

Resources