Android Room database Average query by time in millisec - android

Find average of value in every hour using timeMills
for eaxample i have 20 value in 1h it add and give me the average of every hour average value using timeMills (use timeMills donot use String time).
I am using this query but found 0 values
List<DevicesValuesDB> getAverage();
#Query("SELECT DATE(timeMills / 1000, 'unixepoch') AS timeMills,\n" +
" AVG(value) AS avg\n" +
"FROM devicesvaluesdb\n" +
"GROUP BY timeMills")
List<DevicesValuesDB> gettime();
Model
#Entity
public class DevicesValuesDB {
#PrimaryKey(autoGenerate = true)
public Integer id;
#ColumnInfo(name = "value")
private Double value;
#ColumnInfo(name = "time")
private String time;
#ColumnInfo(name = "timeMills")
private long timeMills;
}

Actually this error says:
Your query returns timeMills,avg and you are storing the result in List<DevicesValuesDB> . With timeMills,avg Room can't create DevicesValuesDB object. So Room expects [id,takenTime,isSync,height,weight,bmi] this fields to create a DevicesValuesDB object.
I think you have imported wrong class for List<DevicesValuesDB> or you didn't post full Class

Related

order by date is not working in android 11 sqllite

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;

Comparing a date in a Room database

I have this Entry data class
#Entity(tableName = "entry")
#Typeconverters(DateConverter::class)
data class Entry(
#PrimaryKey(autoGenerate = false)
var id : String,
var username : String,
var type : String,
var description : String,
var category : String,
var amount : Double,
var date : String,
var lastUpdate : String,
var isDeleted : Boolean)
}
The date field contains a string that represents a date in the "yyyy-MM-dd" format, while the lastUpdate contains a string that represents a date in the "yyyy-MM-dd hh:mm:ss" format. If i store those variables as strings i cannot do SQL comparisons on them since Room does not support SQL's DATE() and DATETIME() datatype and thus queries like this:
#Query(SELECT * FROM entry WHERE date >= :fromDate AND date <= :untilDate)
Will not work properly. Is there any way to fix this?
Well, I see 3 options.
Since your date string is formatted in a nice hierarchical way (year, month, day), you should actually be able to use its natural String sort.
If you need real date sort within a SQL query, you'll have to save your date as real date-field or integer field (Unix epoch timestamp)
If it is okay to sort the date after fetching it from the DB or before storing it in the DB, make yourself familiar with TypeAdapter in Room. It's a simple conversion class where you can convert from String to DateTime and back.
To answer your second question on why such "common" data type is not supported out-of-the box, I can recommend this medium article:
SQLite is a loosely typed database system and stores all values as one
of: NULL, INTEGER, TEXT, REAL or BLOB. You’ll notice that there is no
special date or time type like you may find in other database systems.
Instead they provides the following documentation on how to store
date/time values: SQLite does not have a storage class set aside for
storing dates and/or times. Instead, the built-in Date And Time
Functions of SQLite are capable of storing dates and times as TEXT,
REAL, or INTEGER values
If you think about it further, the question arises: What is a common data type and where does "common" end. Of course, they could provide some TypeConverters, but on the other hand it's a few lines of code for each data type.
Here is an example for a TypeConverter from Date to String and back:
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();
}
}

Query with date comparision on Android with Room

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);

Room SQL query to retrieve entity key and sum of values

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

Broken Insert id of new rows

I'm using Room.
I have this insert method:
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Month month);
My insert method:
for(...){
...
monthDao.insert(new Month(0, monthTitle, monthUrl));
}
Also my model
#Entity(tableName = "news_month_table", indices = #Index(value = {"month_index"}, unique = true))
public class Month {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "month_id")
#Getter #Setter
public long month_id;
#ColumnInfo(name = "month_name")
#Getter #Setter
public String monthName;
#ColumnInfo(name = "month_url")
#Getter #Setter
public String monthURL;
#ColumnInfo(name = "month_index")
#Getter #Setter
public int monthIndex;
My situation:
1) Launch the app and download+insert data (12 rounds of for())
Now base is correct and contains 12 rows with 1-12 id's.
2) I have new data(ex for one row). Launch the app and download+insert data.
Now base contains 13 rows with 1-12 and 24 id.
I dont know what is problem, help me please
You can insert new elements by this code:
MonthDao.insert(new Month(monthDao.getLastMonthId()+1, monthTitle, monthUrl, mIndex));
...
#Query("SELECT * FROM news_month_table ORDER BY month_id DESC LIMIT 1;")
int getLastMonthId();
Just the way to solve the problem.
I think the problem regards the unique index on monthIndex attribute. Please check how you set the value of this attribute. Check on your database the value of associated column.

Categories

Resources