I am getting a weird problem.
with SQL lite query in android 11 devices only.
#Query("SELECT *, SUM(case when isReadMessage = 0 then 1 else 0 end) as countMessage from chat_message_history\n" +
" where messageUser is not null GROUP BY messageUser ORDER by messageDate desc")
LiveData<List<MessagesData>> getAllLiveUniqueUsers();
The DAO class
#Entity(tableName = "chat_message_history", indices = {
#Index(value = "mesId")})
public class MessagesData {
#PrimaryKey(autoGenerate = true)
private int mesId;
private String message;
#TypeConverters(DateConverter.class)
private Date messageDate;
private boolean isReadMessage;
private int countMessage;
private String messageUser;
...}
Date Converter class
public class DateConverter {
#TypeConverter
public static Date toDate(Long timestamp) {
return timestamp == null ? null : new Date(timestamp);
}
#TypeConverter
public static Long toTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
The output should be order by date which is working in android 6 - android 10. In android 11 its not working.
Please help me to solve this problem.
Maybe your query worked coincidentally in previous versions, but actually it is wrong.
It is an aggregation query that counts the number of unread messages of each user of the table chat_message_history.
The flaw in your query is that you want to sort by the date of the message, but which date?
For each user exist many messages.
Which of these dates do you want to be used in the final sorting?
Maybe you want the first or maybe the last.
In this case, SQLite will chose arbitrarily a date (usually it picks the first but this is not guaranteed).
Use an aggregation function like MIN() or MAX() in the ORDER BY clause and also simplify the CASE expression:
SELECT *, SUM(isReadMessage = 0) AS countMessage
FROM chat_message_history
WHERE messageUser IS NOT NULL
GROUP BY messageUser
ORDER by MAX(messageDate) DESC;
Everything I mentioned above about SQLite picking arbitrary values for messageDate also apply the values of the columns returned by SELECT *.
It would be better if you return only aggregated columns like:
SELECT messageUser,
MAX(messageDate) last_date,
SUM(isReadMessage = 0) AS countMessage
FROM chat_message_history
WHERE messageUser IS NOT NULL
GROUP BY messageUser
ORDER by last_date DESC;
Related
I have overhauled my room database from String Dates to Date which is stored as a Long using type converters. I am unable to filter my results for specific times like -7 days or 3 months etc. Here is my configuration:
QUERY
SELECT *
FROM moodBeforetable
WHERE moodBeforetable.workoutDate >= datetime('now', '-1 year')
ORDER BY moodBeforetable.workoutDate DESC
LiveData<List<WorkoutLogsAllPojo>> getAllMoodLogs();
The query works fine when the WHERE clause is commented out, however if I include that line above no data is returned.
This moodBeforetable.workoutDate variable is a DATE but its stored in the database as Long :1590705660000
Type Converter
#TypeConverter
public static Date toDate(Long timestamp){
return timestamp == null ? null : new Date(timestamp);
}
#TypeConverter
public static Long toTimestamp(Date date){
return date == null ? null : date.getTime();
}
Any assistance on the root cause of why the WHERE clause is not returning any data or the specified amount of rows would be greatly appreciated.
Function datetime('now', '-1 year') returns timestamp as '%Y-%m-%d %H:%M:%S', for example 2019-05-28 23:29:42 (docs). To get the number of milliseconds since epoch, use 1000 * strftime('%s', datetime('now', '-1 year')) instead.
I want to query my db with a date comparision with current Date.
Here is my query :
#Query("SELECT * FROM User INNER JOIN AutoLogin ON User.user_Id = AutoLogin.user_Id AND AutoLogin.token_Id = :autoLoginToken AND Autologin.expiration_date > date('now')")
Single<User> getUserByAutoLogin(String autoLoginToken);
Here is my AutoLogin class :
public class AutoLogin implements Parcelable {
#NonNull
#PrimaryKey
#ColumnInfo(name = "token_Id")
private String tokenId;
#NonNull
#TypeConverters(DataTypeConverter.class)
#ColumnInfo(name = "expiration_date")
private Date expirationDate;
#NonNull
#ColumnInfo(name = "user_Id")
private Long userId;
My converters :
#androidx.room.TypeConverter
public static Date toDate(Long value) {
return value == null ? null : new Date(value);
}
#androidx.room.TypeConverter
public static Long toLong(Date value) {
return value == null ? null : value.getTime();
}
The query doesn't work and retrieve no result. I feel this is a problem with the date part of the it. Anybody see what's my error ?
Thanks.
There are 5 functions which SQLite provides:
date(...) returns just the date.
time(...) returns just the time.
datetime(...) returns both the date and time.
julianday(...) returns the Julian Day.
strftime(...) returns a value formatted with your given format
string. The first four can be thought of as variations of strftime
with a pre-defined format.
For more information read the blog
https://medium.com/androiddevelopers/room-time-2b4cf9672b98
You not do same compare with Autologin.expiration_date > date('now')"
expiration_date be like 1579550175468 date('now') be like 2020-01-20
To compare same and want to do by date and no time you can use
#Query("SELECT * FROM User INNER JOIN AutoLogin ON " +
"User.user_Id = AutoLogin.user_Id " +
"AND AutoLogin.token_Id = :autoLoginToken " +
"AND date(Autologin.expiration_date / 1000,'unixepoch') > date('now')")
Other Answer say
#Query("SELECT * FROM User INNER JOIN AutoLogin ON User.user_Id = AutoLogin.user_Id AND AutoLogin.token_Id = :autoLoginToken AND Autologin.expiration_date > strftime('%s', 'now')")
not work well do compare 1579550175468 with 1579551916 it not do / 1000, if it do, it have time to second
Since you used Date.getTime() method in your TypeConverter class, the value stored in DB will be Unix Time.
long getTime() Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.
So in your query, you must compare expiration_date column value with current Unix time. Based on SQLite official website, you can get current Unix time by strftime('%s', 'now') expression. Your query should be like below:
#Query("SELECT * FROM User INNER JOIN AutoLogin ON User.user_Id = AutoLogin.user_Id AND AutoLogin.token_Id = :autoLoginToken AND Autologin.expiration_date > (strftime('%s', 'now') * 1000)")
Single<User> getUserByAutoLogin(String autoLoginToken);
I'm working on an activity which have 6 radio buttons which are(1-All, 2-Today, 3-Yesterday, 4-Last Week, 5-This Month, 6-Last Month) <=These are the names of the radio buttons.
So when I check the Today's radio button and press OK button, it should show me all entries which are inserted in database in today's date, and the reset of radio buttons should give me the result as there names are, as if I check Yesterday, it should give me the data that was stored yesterday.
The problem is I don't know the exact queries for this scenario which will give me the desired data.
I'm using ROOM database and in Dao class I've to write the queries which will give me data according to radio buttons.
There is a Date and Time column which stores the current date and time when the data is store in this table, so I have to match the date of table with the date of Today, Yesterday and so on, and according to that matching the data will be filter.
This is my Entity class(Table) from where I want to get data according to date.
#Entity
public class IncomeExpense {
#PrimaryKey(autoGenerate = true)
private int id =0;
private String type;
private int amount;
private String category;
private String date;
private String time;
private String mode;
private String note;
I just want someone who can write me Dao queries & functions which will give me filter data according to radio buttons.
I have achieved this by using dates in string format. Like Standard format of dates 08-12-2015. In Dao Class I used the following query to get the record for date. note that in my entity class date was also in String format.
#Query("SELECT * from scan_data where sqlDate = date('now') ")
List<Data> getTodayRecord();
For YesterDay Record
#Query("SELECT * from scan_data where sqlDate = date('now','-1 day')")
List<Data> getYesterDayRecord();
For Last Week Record
#Query("SELECT * FROM scan_data WHERE DATE(sqlDate) >= DATE('now', 'weekday 0', '-7 days') AND DATE(sqlDate) != DATE('now') AND DATE(sqlDate) != DATE('now','-1 day')")
List<Data> getLastWeekRecord();
For Month Record
#Query("SELECT * FROM scan_data WHERE strftime('%W',sqlDate) != strftime('%W',date('now')) AND strftime('%Y',sqlDate) = strftime('%Y',date('now')) AND strftime('%m',sqlDate) = strftime('%m',date('now')) AND DATE(sqlDate) != DATE('now', 'weekday 0', '-7 days') AND DATE(sqlDate) != DATE('now') AND DATE(sqlDate) != DATE('now','-1 day')")
List<Data> getLastMonthRecord();
In the beginning, I do private String date instead of private Date date later because of this I can't do the date filter as I want. So use Date data type java.util.Date
I am working on an application where i practice working with Room Persistence Library.
I have a class called expence based on which is the database with fields int amount and Date dob and other.
My goal is to use query below to return the sum of all entries between these dates.
#Query("SELECT SUM(amount) FROM expence WHERE dob BETWEEN date( :start ) AND date( :end ) ")
int newallexpensesFromTo(String start,String end);//
But at the curent state the query doesnt return anything and the textview i want to display the result = 0;
I have used guidance from http://androidkt.com/datetime-datatype-sqlite-using-room/ - to be able to convert from strings to Date and revese.
I have checked maybe its due to different format of the stored date and its the same the one stored in database and the one passed to query.
This is where i try to get the sum of the entries
value2 =db.expenceDao().newallexpensesFromTo(firstdayofmonth,lastdayofmonth);
I have a similar query where without the dates and it returns all entries.
When i add an expense i use DatePicker to add the Date to the dob in database.
Expected result is to receive the sum of entries added between these dates when the query receives the strings with the dates.
Try converting and inserting your startDate and endDate as a long timestamp value into your expense table instead of storing it in some another format.
Now while querying the data, use the timestamp values of your query dates.
For e.g., if you want SUM(amount) between 01-05-2019 and 31-05-2019 than your query would be like:
#Query("SELECT SUM(amount) FROM expense WHERE dob BETWEEN :startDate AND :endDate")
int newAllExpensesFromTo(Long startDate,Long endDate);
Where your startDate and endDate values will be something like 1556668800 & 1559260800 respectively.
For now you can use type converters.
As described in docs for Date your converter in Java should looks like below
public class Converters {
#TypeConverter
public static Date fromTimestamp(Long value) {
return value == null ? null : new Date(value);
}
#TypeConverter
public static Long dateToTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
To apply them, add below code above the class inheriting from RoomDatabase()
#TypeConverters({Converters.class})
Finally you will be able to use it like that
#Query("SELECT SUM(amount) FROM expence WHERE dob BETWEEN :from AND :to")
int newallexpensesFromTo(from: Date, to: Date)
My database contains a list of these "Movement" class:
#PrimaryKey (autoGenerate = true)
private int NumeroDeOperacion;
private int FechaYear;
private int FechaMonth;
private int FechaDay;
private String TipoOperacion;
private String Category;
private String Notas;
private float Quantity;
In one of my queries I'd like to retrieve only Category and Quantity so I created another POJO object like this:
public class Category {
#ColumnInfo(name = "Category")
public String name;
#ColumnInfo(name = "Quantity")
public float quantity;
public Category(){}
}
What I'm triying to get is all the different Category in a specific year and the SUM of all Quantity.
So, let's say I have something like this:
Category Quantity
A 5
B 10
C 5
A 15
B 20
I'd like to get:
Category Quantity
A 20
B 30
C 5
I tried with this query but it is only getting the last entry of each Category:
#Query("SELECT DISTINCT Category, Quantity FROM OperacionesTable WHERE FechaYear = :year GROUP BY CategoryORDER BY Quantity DESC")
LiveData<List<Category>> getGastosCategoryTotalsInYear(int year);
Any help would be much appreciated.
Thanks in advance
To sum the quantities, you have to use SUM.
Also, there is no need for DISTINCT, since GROUP BY already takes care of that. My guess is that you added distinct, because there was an error. The error was there, because Quantity was neither in the group by columns, nor used in an aggregate function. This is typically an error (except in MySQL, which will just give you a random result).
Anyway, this should do the trick:
SELECT
Category,
SUM(Quantity) as TotalQuantity -- Column alias, to give the column a proper name
FROM
OperacionesTable
WHERE
FechaYear = :year
GROUP BY
Category
ORDER BY SUM(Quantity) DESC