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.
Related
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 am working on a project and now I have been stuck on a weird stage.
I know that we can execute any query that has to do anything with database we can write that using:
Cursor cursor = db.rawQuery("SELECT * FROM table_name", null);
But now I want to execute this query:
"SELECT strftime('%s','now','-2 day')"
Generally the above query returns unixepoch time of one day before yesterday.
Does anyone know how can I get this done?
You would handle this query like any other query:
Cursor cursor = db.rawQuery("SELECT strftime('%s','now','-2 day')", null);
try {
if (cursor.moveToFirst()) {
long seconds = cursor.getLong(0);
...
} else {
// cannot happen with this query
}
} finally {
cursor.close();
}
If you want to access the column by name (which is completely pointless if you have only a single column), you can give it an alias:
cursor = db.rawQuery("SELECT strftime(...) AS s", null);
cursor.getColumnIndexOrThrow("s"); // returns zero
...
Please note that for queries that return a single value, there is a helper function:
long seconds = DatabaseUtils.longForQuery(
db, "SELECT strftime('%s','now','-2 day')", null);
Date date = new Date();
will return the current day, if you then subtract X numbers of days, then parse that Date to String with the required format. You can do this with the method SimpleDateFormat:
String newDate = new SimpleDateFormat(pattern).format(date);
where pattern can be something like this "dd-MM-yyyy"
Then, you can add said date to your query.
I want to delete some records from android's database where two conditions are fulfilled.
1. there's a column with the name as sync_status, it should have a value 'C' and
2. there's column which has date.
Now I want to delete only those rows where sync_status is = 'c' and date is less than device's current date. I'm having problem in comparing the device's current date with the date stored in the database and my function deletes all the records.
public int RemoveSyncData(){
DBHelper = new DatabaseHelper(context);
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy ");
Calendar calObj = Calendar.getInstance();
String currentDate = dateFormat.format(calObj.getTime());
Log.e("current date",currentDate);
int rows = db.delete(DATABASE_TABLE_DAILY_ATTENDANCE, KEY_ATTENDANCE_SYN_STATUS + "= ? and " + KEY_ATTENDANCE_DATE_ONLY + " != '" + currentDate + "'", new String[] {"C"});
db.close();
return rows;
}
If you absolutely want to keep the date as a string in the form MM-DD-YYYY in your database column, then the only way to do comparison of those dates is to convert them to seconds using SQLite's strftime function. However, in order to do that, you have to restructure the date as YYYY-MM-DD because your current format is not one that can be used as input to the date and time functions of SQLite.
Here is a sample:
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
Calendar calObj = Calendar.getInstance();
String currentDate = dateFormat.format(calObj.getTime());
String where = KEY_ATTENDANCE_SYN_STATUS + " = ?1 AND "
+ "STRFTIME('%s', SUBSTR(" + KEY_ATTENDANCE_DATE_ONLY + ",7) "
+ "|| '-' || SUBSTR(" + KEY_ATTENDANCE_DATE_ONLY + ",1,5)) < "
+ "STRFTIME('%s', SUBSTR(?2,7) || '-' || SUBSTR(?2,1,5))";
String[] whereArgs = {"C", currentDate};
int rows = db.delete(DATABASE_TABLE_DAILY_ATTENDANCE, where, whereArgs);
If you use yyyy-MM-dd when creating currentDate, you can replace the second instance of the ugly substring + concatenation with just STRFTIME('%s', ?2), but you will still need the first substring + concatenation to transform the column values in the table.
If it's not too late for you to change how your database stores the date, make your life easier by either storing as yyyy-MM-dd (to get rid of all the substring + concatenation above), or better yet store the long date and only worry about converting it to and from MM-dd-yyyy at the java layer.
** EDIT **
Your condition is right it should delete only the rows that meet the condition, just tested it on my SQLite Viewer with some dummy data..
Just be 100% sure that your variable names match the column names and also check the database, if there are some rows which shouldn't be deleted. Maybe there is no entry for today's date and "C" is present in all rows thats why all the records are being deleted.
You can also try the "not so good way":
db.execSQL("delete FROM tableName WHERE KEY_ATTENDANCE_SYN_STATUS = 'C' AND KEY_ATTENDANCE_DATE_ONLY != '"+currentDate+"'");
The above is not a good way as execSQL won't return anything so you won't have anyway to know if it was successful except for checking it yourself.
The above approach is only to test your condition though.
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.
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.