In my application i have to retrieve date from database which lies between some dates.In my database i am storing date as string.I also wrote the query.
This is my sample table:
id item price startdate enddate
1 ass 78 04/08/2012 14/09/2012
2 err 89 04/08/2012 10/09/2012.
3 dffg 44 04/08/2012 18/08/2012
My query is :
public Cursor getIncometitle(String grpsdb,String date) throws SQLException
{
Cursor mCursor = db.rawQuery(
"SELECT * FROM incomexpense WHERE date like '"+date+"' OR enddate > date AND category='Income' AND groups='"+grpsdb +"' ORDER BY date DESC" , null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
In the above condition i am checking enddate>date. In this what is coming is,i think its comparing the dates (04 and 14) and(04and 10),it is greater so all the data is coming .But i don't need that,if enddate month is greater that startdate means i have to get the data.
Thanks in advance..
Leaving aside the SQL injection attack vulnerability (use parameterized queries instead of inserting values directly into your SQL) you should store your dates in a sortable format, e.g. yyyy-MM-dd. At that point, a lexicographic ordering will also give you the right chronological ordering, so your comparisons will work.
If you can, it would actually be better if you could store your dates as dates in the database - it depends on whether your database supports that.
Related
I want to retrieve data of last week or 30 days from my SQLite database, and show it in a ListView. I tried different queries but did not get result. So how can I get data of only last 30 days?
Create database table query :
public String CREATE_DATA_TABLE="CREATE TABLE "+TABLE_DATA+"("
+ DATE + " TEXT," + TIME+ " TEXT,"+STEPS + " TEXT,"+CALORIES +" TEXT," +
DISTANCE+ " TEXT"+")";
Storing data :
public boolean storeData(String date,String time,long stepsTaken,
long caloriesBurned, String distanceCovered){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues values=new ContentValues();
values.put(DATE, date);
values.put(TIME, time);
values.put(STEPS, stepsTaken);
values.put(CALORIES, caloriesBurned);
values.put(DISTANCE, distanceCovered);
long result=db.insert(TABLE_DATA,null, values);
if(result==-1)
return false;
else
return true;
}
Getting data, the query I try to retrieve data is in comment line :
public ArrayList<User> getData(){
calendar=Calendar.getInstance();
dateFormat=new SimpleDateFormat("yyyy-MM-dd");
date=dateFormat.format(calendar.getTime());
ArrayList<User> arrayList= new ArrayList<>();
SQLiteDatabase db=getReadableDatabase();
//String query="SELECT * FROM "+ TABLE_DATA+" WHERE date BETWEEN datetime('now','-30 days') AND datetime('now', 'localtime')";
//Cursor cursor=db.rawQuery(query,null);
Cursor cursor=db.rawQuery("SELECT * FROM "+TABLE_DATA,null);
while (cursor.moveToNext()){
String date=cursor.getString(0);
String time=cursor.getString(1);
long steps=cursor.getLong(2);
long calories=cursor.getLong(3);
String distance=cursor.getString(4);
User user=new User(date,time,steps,calories,distance);
arrayList.add(user);
}
return arrayList;
}
The way I get date and time :
calendar=Calendar.getInstance();
dateFormat=new SimpleDateFormat("dd-MM-yyyy");
timeFormat= new SimpleDateFormat("HH:mm:ss");
date=dateFormat.format(calendar.getTime());
time=timeFormat.format(calendar.getTime());
is it anyway that we can only store data of last 30 days
Your issue is that as the date column starts with the Day then this will be the first character compared so *02-01-1900 is greater than 01-12-2018. This is further complicated as you are using the datetime function that returns the date as YYYY-MM-DD so you are comparing 01-01-1990 with 2018-11-11 (less). However 21-01-1990 would be higher than 2018-11-11 (i.e. 21 is higher than 20).
Therefore you MUST have the dates in the same format for a comparison or sort to return results consistent with expectations.
You have two core solutions :-
Amend your code to store the dates in a a supported format, which just so happens to also suit comparisons and sorting (i.e. YYYY-MM-DD) see Time Strings - SQL As Understood By SQLite - Date And Time Functions.
In which case you query would then work if the date function rather then the datetime function were used as per String query="SELECT * FROM "+ TABLE_DATA+" WHERE date BETWEEN datee('now','localtime','-30 days') AND date('now', 'localtime')";
Reformat the date retrieved from the date column dynamically. e.g. by using :-
SELECT * FROM table_data WHERE
substr(date,7,4)||substr(date,3,4)||substr(date,1,2)
BETWEEN date('now','localtime','-30 days') AND date('now','localtime')
;
Note likewise you should apply the use of localtime consistently (as the above does, bar the date retrieved from the table which should have localtime applied when storing the value).
Proof of Concept
The following is some SQL that could be copied and pasted to an SQLite tool to show that the second option above works :-
DROP TABLE IF EXISTS table_data;
CREATE TABLE IF NOT EXISTS table_data (id INTEGER PRIMARY KEY, date TEXT);
INSERT INTO table_data (date) VALUES
(substr(date('now','localtime','-50 days'),9,2)||substr(date('now','localtime','-50 days'),5,4)||substr(date('now','localtime','-50 days'),1,4)),
(substr(date('now','localtime','-40 days'),9,2)||substr(date('now','localtime','-40 days'),5,4)||substr(date('now','localtime','-40 days'),1,4)),
(substr(date('now','localtime','-30 days'),9,2)||substr(date('now','localtime','-30 days'),5,4)||substr(date('now','localtime','-30 days'),1,4)),
(substr(date('now','localtime','-20 days'),9,2)||substr(date('now','localtime','-20 days'),5,4)||substr(date('now','localtime','-20 days'),1,4)),
(substr(date('now','localtime','-10 days'),9,2)||substr(date('now','localtime','-10 days'),5,4)||substr(date('now','localtime','-10 days'),1,4))
;
-- Result 1 (the data as loaded)
SELECT * FROM table_data;
-- Result2 Data extracted using BETWEEN
SELECT * FROM table_data
WHERE
substr(date,7,4)||substr(date,3,4)||substr(date,1,2)
BETWEEN date('now','localtime','-30 days') AND date('now','localtime')
;
-- Result 3 data from 30 days ago on
SELECT * FROM table_data WHERE
substr(date,7,4)||substr(date,3,4)||substr(date,1,2) >= date('now','localtime','-30 days')
;
Results :-
Result 1
(rows 3,4 & 5 with 30 days)
Result 2
Result 3
Although more time and space has been given to option 2. It is suggested that Option1 is by far the better option as it will reduce unnecessary complexity and be more efficient.
Hello I have and SLQLite database in which I have table water_logs
CREATE TABLE water_logs(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
amount REAL NOT NULL,
icon INTEGER NOT NULL,
date INTEGER NOT NULL);
I store date in milliseconds.
Calendar cal = Calendar.getInstance();
cal.getTimeInMillis();
My problem is I want to get the day from the my date column using strftime function. The problem is tjat java calendar timestamp is different from SLQLite time stamp
1436859563832 --> result from cal.getTimeInMillis();
1436607407--> SELECT strftime('%s','now')
What I'm actually trying to do is to group records by day. The following SQL query works just fine if value of SELECT strftime('%s','now') is paste in the date column
SELECT SUM(amount), date(`date`) FROM water_logs
GROUP BY date(`date`, 'unixepoch')
Seems to me that you are using 2 different value types.
When you use
Calendar cal = Calendar.getInstance();
long time = cal.getTimeInMillis();
The output value is in Milliseconds, as described here.
While when you use
strftime('%s','now')
The output value is in Seconds, as described here.
So, that might be the cause for the mismatch between the two values.
Of course that the value in seconds might undergo some rounding which might change its value a little.
I will try to provide you the best way to store Dates in SQLite database.
1) Always use integers to store the dates.
2) Use this utility method to store the dates into the database,
public static Long saveDate(Date date) {
if (date != null) {
return date.getTime();
}
return null;
}
Like,
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, saveDate(entity.getDate()));
long id = db.insertOrThrow(TABLE_NAME, null, values);
3) Use this utility method to load date,
public static Date loadDate(Cursor cursor, int index) {
if (cursor.isNull(index)) {
return null;
}
return new Date(cursor.getLong(index));
}
like,
entity.setDate(loadDate(cursor, INDEX));
4) You can also order the data by date using simple ORDER clause,
public static final String QUERY = "SELECT table._id, table.dateCol FROM table ORDER BY table.dateCol DESC";
//...
Cursor cursor = rawQuery(QUERY, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
// Process results
}
I have dates stored in a SQLite table in int format (i.e. milliseconds - derived from System.currentTimeMillis()). I now want to query all rows from the table where the date is equal to today's date, but the query below always returns zero, even though file_uploaded_date in the upload_history table is set to today's date in at least 20 rows.
Can anyone tell me what's wrong with my query?
String today = new SimpleDateFormat("d-MMMM-yyyy").format(new Date());
String sql = "SELECT COUNT(*) as uploaded_today from upload_history "
+ "WHERE strftime('%-d-%b-%Y',file_uploaded_date) = strftime('%-d-%b-%Y','" + today + "')";
Cursor cursor = db.rawQuery(sql, null);
if(cursor != null && cursor.moveToFirst()){
int uploadedToday = cursor.getInt(cursor.getColumnIndex("uploaded_today"));
}
I'd say you have your format-strings incorrect.
I don't see a %b argument in the documentation. For month, you would want to use %m. Also %-d doesn't seem right. Use the following format string instead: %Y%m%d.
Further, you are then passing a poorly-formatted string into the query, rather than the int, and relying an sqlite to correct that. Instead, compare to a SimpleDateFormat( "yyyyMMdd" ) without further conversion.
Your code would then look like this:
String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
String sql = "SELECT COUNT(*) from upload_history "
+ "WHERE strftime('%Y%m%d',file_uploaded_date) = '" + today + "')";
Cursor cursor = db.rawQuery(sql, null);
if(cursor != null && cursor.moveToFirst()){
int uploadedToday = cursor.getInt(0);
}
(Note that if you return only one column, you don't have to name it, and can just access the first column for the result.)
Further, please be aware that this query will cause a table-scan every time it's executed, as sqlite needs to convert all the epochs to strings. You'd be better off adding a date column to the table, and update it once:
UPDATE upload_history
SET just_the_date = strftime('%Y%m%d',file_uploaded_date)
This will then allow you to do much quicker searches, and even search by year or month, using the LIKE operator. If your table is very large, you might want to put an index on that column as well.
You can add date in db as a string in date format like yyyy-mm-dd hh-mm-ss and compare the same while retrieving it from database using sql query.
I designing a custom ListView ,which has more child view
I have ideas about sorting the ListViewdata in "Asc" or "Desc" order ,that retrieves data directly from database , but in my case I used CustomSimpleCursorAdapter , I requires to sort data in TextView depending upon the values that is:
today
tomorrow
more than 2 days i.e; 354
CustomSimpleCursorAdapter .java
//Days remaining for BirthDay
String year=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_YEAR));
String month=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_MONTH));
String date=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_DATE));
String remainingDays=BirthdayCalculation.getDaysRemainingForNextBirthDay(year, month, date);
Calendar today=Calendar.getInstance();
int CMonth=(today.get(Calendar.MONDAY)+1);
int CDate=(today.get(Calendar.DAY_OF_MONTH));
//checking whether the BD is on TODAY
if (remainingDays.equals("1") && (CDate==Integer.parseInt(date) && (CMonth)==Integer.parseInt(month))) {
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
viewHolder.txtDaysRemainigValue.setTypeface(fontRoboto_Regular);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#00CC33"));
remainingDays="today";
}
//checking whether the BD is on TOMORROW
else if (remainingDays.equals("1")) {
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#FF0099"));
remainingDays="tomorrow";
viewHolder.txtDaysRemainigValue.setTypeface(fontRoboto_Regular);
}
//checking how many days remaining BD
else{
remainingDays=BirthdayCalculation.getDaysRemainingForNextBirthDay(year, month, date);
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 27);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#990000"));
}
Here's Screen Shot link
When you query your database, you should use an "order by" clause. For example, this method takes the order by clause as the last argument. I don't know how you store your dates and times in your database, but if it's something SQLite can recognize and provide sorting on, then it should work. The following will query for all columns on a table named "table" with no where clause, no "group by" clause, no "having" clause, and order by the time column descending (use ASC for ascending if you want that instead):
database.query("table", null, null, null, null, null, "time DESC");
EDIT
If you can't store the exact data you want (in this case days remaining until an event), I can only see two options:
1). After getting the cursor, you iterate over the results and compose a new sorted list. You could make some kind of model object in java, read the values into it from the cursor, and sort them with a comparator function. At that point you probably would not use a CursorAdapter any more. It's quite easy to build your own ListAdapter - I recommend you watch The World of Listview
2). Since the query methods take strings, you can actually compose more complicated queries so that SQLite provides you the data you DO want (and still sort it for you as well). If your times are stored as longs, you could do something like this:
long currentTime = System.currentTimeMillis();
String timeAsString = Long.toString(currentTime);
String remainingTimeColumn = "(time_column - " + timeAsString + ") AS remaining_time";
// compose query
String table = "table";
String[] columns = new String[] {"column1", "column2", ..., "columnN", remainingTimeColumn};
String order = "remaining_time ASC";
// query
Cursor cursor = database.query(table, columns, null, null, null, null, order);
// later, get remaining time from cursor row
long remainingTime = cursor.getLong(cursor.getColumnIndex("remaining_time"));
In this case "time_column" is the name of the column that stores the event time. What this is doing is creating an additional column with the name "remaining_time", which is calculated from one of the actual column values. The results are then sorted by that synthesized column. The cursor you get back will contain this column and these values, you just need to have the proper column name to access them.
Since I don't know the details of your data format, I can't say this is exactly how your query should look, but the idea should be clear. You can work out the finer details from here...
If you get the data in database, you can use ASC or DESC and put ArrayList.
another way is you can use Collections.sort(). but you must data class implements comparable and overriding compare method.
I have date stored in the form of TEXT in sqllite database. The format is "dd-mm-yyyy". I am making a query to select rows having dates in between two given dates. When I query the database with query dates belonging to the same month, I am getting the results. But, when the date range belong to different month, it returns no rows. For eg:
The problem arises when the dates are something like : 29-03-2013 to 05-04-2013. It returns rows successfully when the dates are between: 02-04-2013 and 05-04-2013. There are rows with entries made on all the dates.
Following are the ways I have tried:
// MySQLiteHelper.COLUMN_DATE_DATE stores column name which is 'date'
// startdate and end date are string in form of mm-dd-yyyy
// MySQLiteHelper.TABLE_NAMES contain table name string
// MySQLiteHelper.COLUMN_MOOD_LEVEL is another column that I wish to get in return
I have tried using the BETWEEN clause and the <= and >=, but no effect to the output. Here is how:
// Method 1:
String selection = MySQLiteHelper.COLUMN_DATE_DATE + " BETWEEN '"+startdate+"' AND '"+ enddate+"' ";
// Method 2:
String selection = MySQLiteHelper.COLUMN_DATE_DATE + " >= '"+startdate+"' AND "+MySQLiteHelper.COLUMN_DATE_DATE+" <= '"+ enddate+"' ";
String []colum = {MySQLiteHelper.COLUMN_MOOD_LEVEL};
Cursor cursor = database.query(MySQLiteHelper.TABLE_NAMES, colum, selection, null, null, null, null);
When I use
cursor.getCount()
to see the number of rows returned, it gives 0. Though there are entries existing in between those dates.
Is their some basic comparison issue that I am missing? I tried looking at some previous questions but didn't work out. I would really appreciate the help.
For string comparisons to work correctly, you must use a format where the most significant field comes first, i.e., yyyy-mm-dd. (This also is the only supported format for SQLite's built-in date functions.)
Before the query , i would like to highlight the correct Date format that is
yyyy-MM-dd
Make sure to save your date in this format.then further the query is following :
Cursor cursor = db.query(TABLE, null, COL_GAME_DATE + " BETWEEN ? AND ?", new String[]{
startDate, endDate},
null, null, null);
I'd suggest you rather fix your database first. Dates should be stored in DATE type, just because of simplicity of further use.