I retrieve data between two dates some how it get correct result and some how it output empty listview when i select dates with month it work properly but when i select dates between more than one month it output empty listview below is my codes
here i declare the variable in DB class
public static final String EX_RowID = "_id";
public static final String EX_Cattype = "Ecattype";
public static final String EX_Date = "Ecdate";
public static final String EX_Price = "Ecprice";
public static final String EX_Type = "itype";
creat table statement
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("CREATE TABLE " + Food_TABLE +"(" +
EX_RowID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
EX_Cattype + " TEXT NOT NULL, " +
EX_Date + " TEXT NOT NULL," +
EX_Price + " INTEGER NOT NULL," +
EX_Type + " TEXT NOT NULL UNIQUE );"
);
}
enter data Method
public long ExEntry(String Ecatgtype, String Edate, String Eprice, String Eitype) {
// TODO Auto-generated method stub
ContentValues cv = new ContentValues();
cv.put(EX_Cattype, Ecatgtype);
cv.put(EX_Date, Edate );
cv.put(EX_Price, Eprice);
cv.put(EX_Type, Eitype);
return ourdatabase.insertOrThrow(Food_TABLE, null, cv);
}
here i access the ExEntry Method
ExMgDB Expentry = new ExMgDB(ADD_EX.this);
Expentry.open();
Expentry.ExEntry(cate, date, price, itype);
Expentry.close();
here i am facing the problem between these two dates variables
public Cursor CstmRpot(String fd, String td) {
// TODO Auto-generated method stub
String[] columns = new String[] {EX_RowID,EX_Cattype, EX_Date, EX_Price, EX_Type };
Cursor c= ourdatabase.query(Food_TABLE, columns, EX_Date + " BETWEEN '" + fd + "'
AND '" + td + "'" , null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
i access it like below
CustemRpt dbcs = new CustemRpt();
Cursor cursor = CstDB.CstmRpot(frmdate,tondate);
There are two major solutions. All solutions have in common, that the column containing the date has to be ordered somehow. If this order is destroyed your data is corrupt and your queries cannot return the expected results!
1. Save your Dates as INTEGER in your database and use a method to map Dates to a number:
A possible way is to use Date.getTime () to map Dates to numbers, but there are many others. Important is that
equal dates get the same number and
that a date that is after another date gets a bigger number.
This way ordering will be correct for sure.
To achieve this with `Java.util.Date.getTime() you only have to set the time to 0:00:00:000 if you want to store date only.
For example:
"CREATE TABLE " + Food_TABLE +"(" +
EX_RowID + "INTEGER PRIMARY KEY AUTOINCREMENT, " +
EX_Cattype + " TEXT NOT NULL, " +
EX_Date + " INTEGER NOT NULL," +
EX_Price + " INTEGER NOT NULL," +
EX_Type + " TEXT NOT NULL UNIQUE );"
private static String dateOnly(java.util.Date d) {
Calendar cal = Calendar.getInstance(); // locale-specific
cal.setTime(d);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return Long.toString(cal.getTimeInMillis());
}
public Cursor CstmRpot(java.util.Date fd, java.util.Date td) {
// TODO Auto-generated method stub
String[] columns = new String[]{EX_RowID,EX_Cattype, EX_Date, EX_Price, EX_Type };
Cursor c= ourdatabase.query(Food_TABLE, columns, EX_Date + " > " + dateOnly (fd) + " AND " + EX_Date + " < " + dateOnly(td), null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
If you don't use different timezones the dateOnly(java.util.Date d) can be optimized.
Of course you can also use JODA-time.
2. Save your Dates as TEXT
If you choose this method your queries that are comparing the date-column are going to be a bit slower, but the entries in the database are human readable which doesn't have t be the case with method 1.
TEXT-columns are ordered with BINARY by default, which means memcmp() is used to compare the values and to determine which value is greater or if the values are equal. (Remember x BETWEEN a AND b means x <= a AND x >= b.)
You can examine the work of memcmp() with this function memcmp().
To ensure you get the right results you have to ensure the following:
All date-values in your database have to have the same text length.
All date-values in your database have to be in the same Format. The bigger date-parts (year) have to be before the smaller date-parts (month).
All Parameters for date-values in queries have to follow these rules too.
A possible date-format may look like this: yyyy-MM-dd (for example 2014-02-04 or 2000-12-24).
Advices
Use android.widget.DatePicker instead of Edittext for getting dates as input.
Never use any texts you got from user inputs directly in your query, but validate them before (see sql-injection).
Read some articles about how Strings are compared.
Try SELECT * FROM "your table" WHERE date BETWEEN "from date" AND "to date";
you need to store date inform of yyyy-mm-dd and then use this method simply call getWeekData(start_date, end_date);
public Object getWeekData(String start_date, String end_date) {
if (!mDataBase.isOpen())
openDataBase();
Object data = new Object ();
// Select All Query
String query = (String) ("Select * from " + TBL_NAME
+ " where " + (COL_DATE + " between '" + start_date + "' AND '" + end_date + "'"));
Cursor cursor = mDataBase.rawQuery(query, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
//get data over here
} while (cursor.moveToNext());
}
// closing connection
cursor.close();
close();
return data;
}
we have Two solution for this question
one is we need to convert date and time into milliseconds, and take long data type in
Sqllite database and save values(converted date and time). And the write query like "SELECT
data, start_date, end_date from tablename WHERE start_date > end_date".
Second way is you need to save start and end date+time(yyy-MM-dd HH:mm:ss) in string format
in Sqllite database, and you need to query like this,
"SELECT datetime_start,datetime_end FROM tablename WHERE(( DATETIME(atetime_start) >=
DATETIME ("+"'"+entry_start_time+"'"+")" +" AND DATETIME(datetime_end) < DATETIME
("+"'"+entry_end_time+"'"+")); .
Related
I'm trying to update data in rows in my DB, but i catch error that there's no such column (no such column 'Moscow' or another)
This is DBHelper code:
public static final String tableName = "currentWeather";
public static final String KEY_ID = "_id";
public static final String cityName = "city";
public static final String cityTemp = "temperature";
And creating DB:
sqLiteDatabase.execSQL("create table " + tableName + "(" + KEY_ID + "
integer primary key autoincrement,"
+ cityName + " text," + cityTemp + " text, " + " UNIQUE(" + cityName +
"))");
and error shows when i try to execSQl in response:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " +
DBHelper.cityTemp + "=" +
response.body().getForecastMain().getTemp() + "
WHERE "
+ DBHelper.cityName + "=" + cityName);
I expect to update temperature data in rows by cityName
cityName and response.body().getForecastMain().getTemp() are strings and they should be passed surrounded with single quotes to the sql statement:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " + DBHelper.cityTemp + "='" + response.body().getForecastMain().getTemp() + "'" +
"WHERE " + DBHelper.cityName + " = '" + cityName + "'"
);
But the recommended and safe way of doing the update is with the use of ContentValues and ? as placeholders for the parameters:
ContentValues cv = new ContentValues();
cv.put(DBHelper.cityTemp, String.valueOf(response.body().getForecastMain().getTemp()));
int rows = sqLiteDatabase.update(
DBHelper.tableName,
cv,
DBHelper.cityName + " = ?",
new String[] {cityName}
);
You can examine the value of the integer variable rows.
If it is 1 this means that 1 row was updated (because cityName is unique) so the update was successful.
I think you have changed column name or add new one (city). So you can fix it by two ways
By uninstall the application from phone
Add column name in upgrade method.
Example:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER DEFAULT 0");
}
}
The thing is you need to wrap the values after the = sign in single quotations in the UPDATE statement. As for digits they work in both cases.
For example here is the correct syntax
UPDATE currentWeather
SET temperature = 45
WHERE
city = 'Moscow'
But in your code I'm assuming cityName has the value Moscow without the single quotation marks so the converted SQL code will be like this
UPDATE currentWeather
SET temperature = 45
WHERE
city = Moscow
Now the sql interpreter will think Moscow is some database object or column or something and not a literal value. So you need to surround your values in single quotation marks.
Also consider What the data type of response.body().getForecastMain().getTemp() is.
If it's int you have to parse it or something, as the data type of the related column is Text.
I'm currently developing an application for android and I'm trying to get the last entry in my database ordered by a column that contains a String with the date and time.
My problem is that the result of the query is always the first date and not the last one.
I already tried ordered my column by "date", "datetime" and by "DESC" and "ASC".
the following is the query to create the table that contains the date in question
private static final String CREATE_TABLE_TIMBRAGE="CREATE TABLE "
+ TABLE_TIMBRAGE + "(" + COLUMN_T_TIMBRAGE_PK_TIMBRAGE + " INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, "
+ COLUMN_T_TIMBRAGE_DATETIMBRAGE + " DATETIME NOT NULL, " + COLUMN_T_TIMBRAGE_INOUT + " INT NOT NULL, "
+ COLUMN_T_TIMBRAGE_FK_EMPLOYE + " INT NOT NULL, "+ "FOREIGN KEY(" + COLUMN_T_TIMBRAGE_FK_EMPLOYE + ") REFERENCES " + TABLE_EMPLOYE + "("+COLUMN_T_EMPLOYE_PK_EMPLOYE+") "
here is my formatter for the dates
SimpleDateFormat FORMATTER=new SimpleDateFormat("dd.MM.yyyy'-'HH:mm:ss", Locale.FRANCE);
here is how I'm adding into this table
ContentValues values = new ContentValues();
values.put(COLUMN_T_TIMBRAGE_DATETIMBRAGE, FORMATTER.format(timbrage.getDateTimbrage()));
values.put(COLUMN_T_TIMBRAGE_INOUT, timbrage.getInOut());
values.put(COLUMN_T_TIMBRAGE_FK_EMPLOYE, timbrage.getFK_Employe());
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_TIMBRAGE, null, values);
db.close();
and finally here is my query that should get the last entry
String query2 = "Select * FROM " + TABLE_TIMBRAGE + " WHERE " + COLUMN_T_TIMBRAGE_FK_EMPLOYE + " = \"" + FK_Employe + "\"" + " ORDER BY datetime("+ COLUMN_T_TIMBRAGE_DATETIMBRAGE +") ASC LIMIT 1 ";
Cursor cursor2 = db.rawQuery(query2, null);
The result that I get is
"Thu May 23 15:34:58 GMT+02:00 2019"
but I should get
"Thu May 23 15:56:32 GMT+02:00 2019"
Instead of saving date as a String, it is a good idea to convert said date to milliseconds since 01 Jan 1970. This way, the sorting is very straightforward and comparing numbers is more efficient. You can then, upon querying the data convert the milliseconds to a formatted Date.
Try this:
SELECT * FROM + YOUR_TABLE_NAME + ORDER BY + YOUR_DATETIME_COLUMN_NAME + DESC
And I have a suggestion that you should use DATETIME DEFAULT CURRENT_TIMESTAMP as your DATETIME column type. This auto-updates the DATETIME whenever you insert or update the row.
I have database with 4 columns int id | String data | String date | int boot and i have some data in it. I have method getRow(String s) when i call it with string for id or data and change query to that option it works but when i´m trying to get row with equal date it won´t pass cursor.moveToFirst condition.
Here is my code:
String CREATE_TABLE = "CREATE TABLE "
+ TABLE_NAME + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_DATA
+ " TEXT," + COLUMN_DATE + " TEXT," + COLUMN_BOOT + " Integer" + ")";
public String getRowID(String id){
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.rawQuery("select * from " + TABLE_NAME + " where " + COLUMN_ID + " = " + id, null);
if (c != null && c.moveToFirst()) {
//loggin succes
return "string";
}else return null;
}
public String getRowDate(String date){
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.rawQuery("select * from " + TABLE_NAME + " where " + COLUMN_DATE + " = " + date, null);
if (c != null && c.moveToFirst()) {
//loggin succes
return "string";
}else return null;
}
myDb.getRowID("1"); returning something
myDb.getRowDate("02122016"); returning null
I have two rows in my database.
1 | 0.19 | 01122016 | 0
2 | 0.19 | 02122016 | 0
Be wary when comparing integers and strings. You may wonder why SQLite would be comparing integers at all since your arguments are strings, until you consider that your raw query looks like this:
select * from TABLE where DATE = 02122016
That value is interpreted as an integer and converted to text, but it loses the leading zero in the process. You can verify this with a sqlite3 shell:
sqlite> select 02122016;
2122016
sqlite> select '02122016' = 02122016;
0 -- false
sqlite> select cast(02122016 as text);
2122016
The simplest fix is to quote the value using a method from DatabaseUtils:
String escaped = DatabaseUtils.sqlEscapeString(date);
String query = "select * from " + TABLE_NAME + " where " + COLUMN_DATE + " = " + escaped;
A better fix would be to use a placeholder argument instead. Note that Android binds all arguments as strings:
String query = "select * from " + TABLE_NAME + " where " + COLUMN_DATE + " = ?";
db.rawQuery(query, new String[]{date});
However, my advice would be to not use rawQuery() and instead use one of the real query() methods. Here's a good example.
Lastly, perhaps you should consider a different format for storing dates. In practice I usually either store an INTEGER column with a unix timestamp (seconds or milliseconds since epoch), or I use a TEXT column with values in the yyyy-MM-dd format since this is implicitly supported by numerous datetime functions in SQLite.
So i am trying to insert some data in the internal sqlite database but after i run the insert no data has been added. There are, as far as i can see no errors in the logs and every debug log i put into it is shown. If i try to run the query that is returned in the log in sqlitestudio it works without a problem so i haven't got a clue as to what is going wrong.
#Override
public void onCreate(SQLiteDatabase db) {
String SQL = pictureTable();
db.execSQL(SQL);
}
private String pictureTable() {
return "CREATE TABLE geophoto_db_pictures ( picid integer,"
+ "name varying character(50),"
+ "city varying character(20) NOT NULL,"
+ "zipcode varying character(20) NOT NULL,"
+ "country varying character(20) NOT NULL,"
+ "picdate datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "tags varying character(200),"
+ "image varying character(200) NOT NULL,"
+ "uploaded integer NOT NULL DEFAULT 0, PRIMARY KEY (picid))";
}
#Override
public void savePicture(Picture pic) {
Log.d(LOG_TAG, "saving picture started. Data: " + pic.getName());
// clean the inputs
String name = pic.getName();
String city = pic.getCity();
if (city != null) {
city = "'" + city + "'";
}
String country = pic.getCountry();
if (country != null) {
country = "'" + country + "'";
}
String zip = pic.getZipcode();
if (zip != null) {
zip = "'" + zip + "'";
}
String tags = tagsToString(pic.getTags());
String image = pic.getImage();
// Insert Query, all possible null values on "not null" rows will be
// replaced by a default value.
String SQL = "INSERT INTO geophoto_db_pictures(name, city, zipcode, country, tags, image)"
+ "VALUES('"
+ name
+ "',"
+ "IFNULL("
+ city
+ ", 'Unknown')"
+ ","
+ "IFNULL("
+ zip
+ ", 'Unknown')"
+ ","
+ "IFNULL("
+ country + ",'Unknown')" + ",'" + tags + "','" + image + "')";
Log.d(LOG_TAG, SQL);
executeWriteQuery(SQL);
ArrayList<Picture> list = getAllPictures();
Log.d(LOG_TAG, "Size :"+list.size());
}
private Cursor executeWriteQuery(String query){
Log.d(LOG_TAG, "execute write query");
SQLiteDatabase db = getWritableDatabase();
Cursor response = db.rawQuery(query, null);
Log.d(LOG_TAG, "write query executed");
return response;
}
All tips/help greatly appreciated!
Thomas
Try to put a semicolon at the end of table creation query. In your case as show below
private String pictureTable() {
return "CREATE TABLE geophoto_db_pictures ( picid integer,"
+ "name varying character(50),"
+ "city varying character(20) NOT NULL,"
+ "zipcode varying character(20) NOT NULL,"
+ "country varying character(20) NOT NULL,"
+ "picdate datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "tags varying character(200),"
+ "image varying character(200) NOT NULL,"
+ "uploaded integer NOT NULL DEFAULT 0, PRIMARY KEY (picid));";
}
While providing a query through an external String, you will need to provide SQL query with an end of statement ;. Using the primitive SQLite does not require ; as it just takes arguments and create function query itself. I have experienced both cases and I ended up understanding the way I have put it here.
The problem you are facing is that you are trying to use rawQuery() to insert a record, when you should be using execSQL() instead (see this answer).
So, the correct code for executeWriteQuery would be as follows:
private void executeWrite(String command){
Log.d(LOG_TAG, "execute write");
SQLiteDatabase db = getWritableDatabase();
db.execSQL(command);
Log.d(LOG_TAG, "write executed");
}
Also, consider using insert() instead as that will allow you to get a return value to determine whether or not the data was inserted successfully.
I am attempting to enter values such as "0.20" within a table but when I display it within an activity it shows "0.2". I am uncertain as to why the '0' is being removed i.e. incorrect structure of the table, insertion, or being returned.
My table is created as followed:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_NAME
+ " TEXT NOT NULL, " + KEY_SWIMMERLAPS + " INT NOT NULL, "
+ KEY_SPONSOR + " DEC(4,2) NOT NULL );");
I then insert the data:
public long addSwimmer(String name, String laps, String sponsor) {
int i = Integer.parseInt(laps);
ContentValues cv = new ContentValues();
cv.put(KEY_NAME, name);
cv.put(KEY_SWIMMERLAPS, i);
cv.put(KEY_SPONSOR, (new DecimalFormat("0.00##")).format(0.20));
return ourDatabase.insert(DATABASE_TABLE, null, cv);
}
and then return the sponsorship data:
public String getSwimmerSponsors() {
String[] columns = new String[] { KEY_SPONSOR };
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, null, null, null,
null, KEY_SWIMMERLAPS + " DESC");
String result = "";
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
result = result + c.getString(0) + "\n";
}
return result;
}
Edit - I display the returned result in my layout as follows:
String sponsors = swimmerDb.getSwimmerSponsors();
tvSponsor.setText(sponsors);
Thanks.
Because you're displaying an unformatted Java variable, and leading/trailing 0s are suppressed.
If you want to format it with a specific layout, use one of the printf/format variants:
printf("%.2f", num); // Etc.
When talking numbers 0.20 and 0.2 are exactly the same. If you want to keep the formatting than I suggest you insert the value as a formatted string.
cv.put(KEY_SPONSOR,0.20);
turns into
cv.put(KEY_SPONSOR, (new DecimalFormat("0.00##")).format(0.20));
EDIT: If you go this way, don't forget to change the KEY_SPONSOR column type from DEC to TEXT
SQLite does not offer DECIMAL or any similar type where you can specify the precision. The only data type with decimal places is REAL and that is how your number is being handled.
If you need specified precision you can multiply (by 100, in this case) and store as INTEGER, or use a TEXT column.