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.
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
}
All!
My code:
This method needs to check current date and if it is changed it will make new record in db.
public static void updateHintBase(SQLiteOpenHelper database)
{
String currentDate = getDateInString();
SQLiteDatabase db = database.getReadableDatabase();
Cursor cursor = db.query("HINTS",
new String[]{"CURRENT_DATE"},
"CURRENT_DATE = ?",
new String[]{currentDate},
null, null, null);
int countRow = cursor.getCount();
cursor.close();
if (countRow==0)
{
ContentValues values = new ContentValues();
values.put("CURRENT_DATE", currentDate);
values.put("SPENT", 0);
values.put("TOTAL", TOTAL_HINTS);
db.insert("HINTS", null, values);
}
db.close();
}
This method transforms date to String :
private static String getDateInString()
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date = sdf.format(new Date());
return date;
}
Table structure:
db.execSQL("CREATE TABLE HINTS (CURRENT_DATE TEXT PRIMARY KEY , "
+ "SPENT INTEGER,"
+ "TOTAL INTEGER);");
But my code doesn't work. First time it works, but the second time when date was changed my first method finds element in cursor anyway...
For example:
1) Today 16.01.2017. My application was executed. Everything is all right.
2) Today 18.01.2017. My application was executed and I expect that method cursor.getCount() will return to me 0 and new row with new date will be created. But it returns to me 1. etc.
You may have to set cursor to cursor.MoveToNext() You are also closing the cursor before you get the information which may be the problem. Lastly looping through the cursor is the most efficient way to get more that one piece of information.
Please try this query:
cursor = db.rawQuery("select count(YOUR_ID) from HINTS where CURRENT_DATE = ? ", new String[] {currentDate});
Oh! I found my mistake!
Word "CURRENT_DATE" is reserved by SQL.
https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions037.htm#SQLRF00628
That's why my code works incorrect.
I change "CURRENT_DATE" to "TODAY" an now it works fine.
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 am accessing Android MMS database to get the date of MMS message:
Uri mmsUri = Uri.parse("content://mms/");
ContentResolver contentResolver = getContentResolver();
String[] projection = {"_id", "date"};
Cursor cursor = contentResolver.query(mmsUri, projection, null, null, null);
long dateVal = cursor.getLong(cursor.getColumnIndex("date"));
//This date is always 1970
Date mmsDate = new Date(dateVal);
But the date I get is always 1970. Then, I found an answer for this. I need to set the projection to null (to return all columns) and then use the following code to get date value:
//A mystery column of index 2
long timestamp = cursor.getLong(2) * 1000;
//It works !
Date mmsDate = new Date(timestamp);
Everything until here is fine. But, now instead of geting all rows from MMS database, I need to select those rows which were sent after a certain date, which means I need to use selection & selection argument. Something like:
String selection = NAME_OF_MYSTERY_COLUMN_IDX_2 > minDate
Cursor cursor = contentResolver.query(mmsUri, projection, selection, null, null);
But I have no idea what is the name of the column with index 2, how could I achieve what I need ? Is there a workaround?
Your first code block is correct, except for the Date instantiation. That constructor expects the time in milliseconds, but the MMS table keeps dates in seconds. To correct this, simply multiply the value returned from the query by 1000.
Date mmsDate = new Date(dateVal * 1000);
For future reference, the Cursor#getColumnName() method will give you the String name for a given column index.
You can try this.
String selection = "date_sent" > minDate
https://developer.android.com/reference/android/provider/Telephony.BaseMmsColumns.html#DATE_SENT
I would like to check with you ,
I would like to do a summary for my application.
Such that it will give me an average for my price based on month.
This mean that I've a set of records, which I've already filter by month.
If month = Jan, I would like to get all the Jan data and divide by the number of days in the month.
Right now,
I'm only able to take out the months.
I would like to check,
If I would want to do " would like to get all the Jan data and divide by the number of days in the month. ", how can I do it?
Can anyone suggest to me?
Im new to android, and trying to learn things.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.summary);
monthDate = (EditText)findViewById(R.id.month);
avgPrice = (TextView)findViewById(R.id.showavfPriceTV);
exFuel = (TextView)findViewById(R.id.showexFuelTV);
avgFC = (TextView)findViewById(R.id.showavgFCTV);
doneButton = (Button)findViewById(R.id.doneBTN);
exitButton = (Button)findViewById(R.id.exitBTN);
// First we need to make contact with the database we have created using
// the DbHelper class
AndroidOpenDbHelper openHelperClass = new AndroidOpenDbHelper(this);
// Then we need to get a readable database
SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();
// We need a a guy to read the database query. Cursor interface will do
// it for us
// (String table, String[] columns, String selection, String[]
// selectionArgs, String groupBy, String having, String orderBy)
Cursor cursor = sqliteDatabase.query(
AndroidOpenDbHelper.TABLE_NAME_LOG, null, null, null, null,
null, null);
// Above given query, read all the columns and fields of the table
startManagingCursor(cursor);
// Cursor object read all the fields. So we make sure to check it will
// not miss any by looping through a while loop
while (cursor.moveToNext()) {
// In one loop, cursor read one undergraduate all details
// Assume, we also need to see all the details of each and every
// undergraduate
// What we have to do is in each loop, read all the values, pass
// them to the POJO class
// and create a ArrayList of undergraduates
String id = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_ROWID));
final String date = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_DATE));
String price = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_PRICE));
String pump = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_FUEL));
String cost = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_COST));
String odm = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_ODM));
String preodm = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_PREODM));
String fcon = cursor.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.KEY_CON));
// If you don't close the database, you will get an error
sqliteDatabase.close();
Log.i("FuelLog", "dataBundle " + date);
monthDate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// showDialog(DATE_DIALOG_ID);
DialogFragment newFragment = new DatePickerFragment();
newFragment.show(getFragmentManager(), "datePicker");
}
});
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (monthDate.getText().toString().equals(date.subSequence(3,9).toString()))
{
Log.d("MONTHDATE","date : "+ monthDate.getText().toString());
Log.d("BBUNDLEDATE","date : "+ (date.subSequence(3,9).toString()));
Intent intent=new Intent(getApplicationContext(),homeActivity.class);
startActivity(intent);
}
else
{
Intent intent=new Intent(getApplicationContext(),about.class);
startActivity(intent);
Log.d("ELSEMONTHDATE","date : "+ monthDate.getText().toString());
Log.d("ELSEBUNDLEDATE","date : "+ (date.subSequence(3,9).toString()));
}
}
});
}
}
Supposing you have the SUM of your monthly data for a single month,
Cursor cur = myDB.rawQuery
("SELECT SUM(Price) FROM Prices WHERE Month = 1", null);
if(cur.moveToFirst())
{
return cur.getInt(0);
}
Even better, you can have a single query to get the months and the summed prices per each month of the given year:
String sql = "SELECT Month, SUM(Price) FROM Prices WHERE Year = ? GROUP BY Month ORDER BY Month";
Divide your single monthly datum by:
Calendar cal = new GregorianCalendar(2014, Calendar.JANUARY, 1); // Specify an year and a month basing on your datum
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
Just keep in mind this: (fromm the SQLite reference site)
sum(X) and
total(X)
The sum() and total() aggregate functions return sum of all non-NULL values in the group. If there are no non-NULL input rows then sum() returns NULL but total() returns 0.0. NULL is not normally a helpful result for the sum of no rows but the SQL standard requires it and most other SQL database engines implement sum() that way so SQLite does it in the same way in order to be compatible. The non-standard total() function is provided as a convenient way to work around this design problem in the SQL language.
The result of total() is always a floating point value. The result of sum() is an integer value if all non-NULL inputs are integers. If any input to sum() is neither an integer or a NULL then sum() returns a floating point value which might be an approximation to the true sum.
Sum() will throw an "integer overflow" exception if all inputs are integers or NULL and an integer overflow occurs at any point during the computation. Total() never throws an integer overflow.
ALSO NOTE
It's always a good idea to put dummy values (0.0) for months where no price is specified