I have a room database. I have a column for date and it's saved as string.
I used this query for sort my column :
#Query("SELECT * FROM session WHERE class_id = :classId ORDER BY session_date ASC")
List<SessionEntry> getAllSessions(int classId);
Result :
1398/11/25
1398/11/29
1398/12/5
1398/2/14
1398/4/25
1398/6/17
1398/6/30
1398/7/9
1398/9/14
but i want to sort like this :
1398/2/14
1398/4/25
1398/6/17
1398/6/30
1398/7/9
1398/9/14
1398/11/25
1398/11/29
1398/12/5
Is there any way I could order by Date as String without modifying the database structure ?
in my case it is working as I have like float type formate :
#Query("SELECT * FROM growthlogdata WHERE babyid = :childid Order By CAST(dateGrowth AS FLOAT) ASC")
List<SessionEntry> getAllSessions(int classId);
First answer, don’t store dates as strings, use a proper date datatype.
However, if I understand correctly that your SQLite database hasn’t got a date datatype, #matdev is correct: The best solution is to change the format into yyyy-mm-dd. This conforms with ISO 8601 and will sort chronologically.
I found a solution but it's not best.
This way is for when you can't change your Date Column from String to another type
List<SessionEntry> sessionEntries = mDb.sessionDao().getAllSessions(classId);
Collections.sort(sessionEntries, comparing(SessionEntry::convertStringToDate));
Session Entry :
public class SessionEntry {
.
.
.
public Date convertStringToDate() {
try {
return new SimpleDateFormat("yyyy/MM/dd").parse(getSessionDate());
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
Related
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();
}
}
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 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)
I want to select multiple column from SqLite through Room Library in Android SDK environment.
Below is the query for selecting it.
#Query("SELECT ID,message,timestamp FROM Chat_Message WHERE groupID =:groupID
ORDER BY timestamp DESC LIMIT 1")
public List get_last_msg_ID_timestamp (String
groupID);
My Last_Msg_Detail class which is define under main class is as follows:-
public class Last_Msg_Detail {
public Integer ID;
public String message;
public Long timestamp;
}
For accessing this three variable have created below method :-
Last_Msg_Detail last_record_t = new Last_Msg_Detail();
public Last_Msg_Detail get_last_msgand_time_stamp(String groupID){
List<Last_Msg_Detail> last_record =
chat_messageDao.get_last_msg_ID_timestamp(groupID);
last_record_t = last_record.get(0);
return last_record_t;
}
On Rebuilding Project, getting follow error
1. error: Cannot figure out how to save this field into database. You can
consider adding a type converter for it.
2. error: Not sure how to convert a Cursor to this method's return type
Kindly advise how to resolve.
Thanks in advance for your help.
your method return custom object and the object has a lot of fields.
so, when you try to return specific columns, you try to return a new object. so the error occurs.
to solve the problem, create a new object for the selected columns. it has to has these fields.
ID,message,timestamp
and use the object in your method
#Query("SELECT ID,message,timestamp FROM Chat_Message WHERE groupID =:groupID ORDER BY timestamp DESC LIMIT 1")
public List<NEW_OBJECT> get_last_msg_ID_timestamp (String groupID);
Hi i want to query for all of the rows/objects in the db table that have have a timeStamp in ISO8601, bigger than a date baseDate(ISO8601) , Im using the Ormlite as framework,so please suggest a solution that uses Ormlite.
Here is a simple example of my model.
#DatabaseTable(name="testTable")
class testTable
{
#DatabaseField(id = true)
int id
#DatabaseField
String timeStamp
}
Thanks
Try to use :
private TimeStampType timeStamp;
As the data type and "QueryBuilder" with a where clause.