My database currently has a column which looks like this:
id | timestamp
-- | ---------
1 | 07/29/2014
2 | 07/30/2014
3 | 07/30/2014
4 | 2014-07-30
5 | 2014-07-30
I am trying to format any rows of timestamp in the old format, to the new format
in this example, rows 1-3 need to be reformatted
07/29/2014 -> 2014-07-29
07/30/2014 -> 2014-07-30
07/30/2014 -> 2014-07-30
I am not that familiar with SQL/SQLite but and from to come up with some sql i can execute once to see if there are any rows in the old format, and if they are, replace them with the equivalent of the new format.
any help would be greatly appreciated.
I believe I am trying to do what this user here wrote but couldn't get it to work
https://stackoverflow.com/a/7781473/433866
Thanks!
Here are the results I am getting with some real data:
timestamp column old / timestamp converted
07/25/2014 -> 01/04/0031
05/21/2014 -> 11/04/0026
01/25/2013 -> 07/06/0030
09/25/2000 -> 02/21/0031
07/25/2015 -> 01/05/0031
07/25/2016 -> 01/06/0031
07/25/1999 -> 12/20/0030
07/25/1986 -> 12/07/0030
and here is the method i am using
// REFORMAT DATES
public void reformatDates(String table){
SQLiteDatabase db = this.getWritableDatabase();
String selectQuery = "SELECT * FROM " + table;
Cursor cursor = db.rawQuery(selectQuery, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
do {
db.execSQL("update Food set timestamp = substr(timestamp,4,2) || '-' || substr(timestamp, 1,2) || '-' || substr(timestamp, 7) where timestamp LIKE '%/%'");
}
while (cursor.moveToNext());
}
cursor.close();
db.close();
}
Got it this time!
// REFORMAT DATES
public void reformatDates(String table){
SQLiteDatabase db = this.getWritableDatabase();
String selectQuery = "SELECT * FROM " + table;
Cursor cursor = db.rawQuery(selectQuery, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
do {
db.execSQL("update " + table + " set timestamp = substr(timestamp, 7) || '-' || substr(timestamp, 1,2) || '-' || substr(timestamp,4,2) WHERE timestamp LIKE '%/%'");
}
while (cursor.moveToNext());
}
cursor.close();
db.close();
}
Related
I have two method's in my SQLite Database in which i check if there is in a table certain column that is the same as a String after it i print all other columns on the same row and with the second method i check if a column from the first method equals to a data stored in a column of another table.
But i'm having issues when i check for a data that is not in the database here is an example:
TABLE CODART_BARCODE
CODART_CODART CODART_BARCODE CODART_PXC
123 1234 1
TABLE CODART_ART
DESCR_ART PVEN_ART PACQ_ART CODART_ART
PIZZ 1.50 12 123
So if in an EditText i insert 123 that equals to CODART_CODART and there is also 123 in CODART_ART from the other table i will print "PIZZ 1.50 12" but if i insert in the EditText 12356 the app crash because there is no same data in DB how can i prevent that app crash? i mean if there is no same data can i make a Toast that says "no data" or something like this but not making the app crash?
Here are the two methods from DB:
public String dbRawSearch(String id) {
StringBuilder dbString = new StringBuilder();
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = " + id;
//Cursor points to a location in your results
#SuppressLint("Recycle") Cursor c = db.rawQuery(query, null);
//Move to the first row in your results
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
db.close();
return dbString.toString();
}
// FETCH codArt from Articoli
public String dbRawArticoli(String id){
StringBuilder dbString = new StringBuilder();
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = " + id;
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_ART")) != null) {
dbString.append(c.getString(c.getColumnIndex("DESCR_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PVEN_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PACQ_ART"))).append("\n");
}
c.moveToNext();
}
db.close();
return dbString.toString();
}
Your issue is that you are not correctly enclosing the search argument and thus if the value is non numeric then SQLite will consider that you are comparing a column, hence the no column found.
Lets say assuming you use :-
String result1 = yourdbHelper.dbRawSearch("123");
Then the resultant SQL will be :-
SELECT * FROM CODART WHERE CODART_BARCODE = 123;
That is fine as the search is looking for a number.
However if you used:-
String result1 = yourdbHelper.dbRawSearch("Fred");
Then the resultant SQL will be :-
SELECT * FROM CODART WHERE CODART_BARCODE = FRED
This would fail because FRED is non-numeric, and is therefore interpreted as saying SELECT all columns from the table CODART where the column named COADRT has the same value as the column named FRED, there is no column named FRED.
The result is that you get an error along the lines of :-
06-11 11:34:12.653 1373-1373/soanswers.soanswers E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{soanswers.soanswers/soanswers.soanswers.MainActivity}: android.database.sqlite.SQLiteException: no such column: FRED (code 1): , while compiling: SELECT * FROM CODART WHERE CODART_BARCODE = FRED
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
The Fix
The resolution is simple, and that is to enclose the argument being searched for in single quotes so that the SQL is then :-
SELECT * FROM CODART WHERE CODART_BARCODE = 'FRED'
Note that is just one example. However you will need to makes similar changes to both methods (dbRawSearch and dbRawArticoli), as shown :-
To do this you could change :-
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = " + id;
to :-
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = '" + id + "'";
and also change :-
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = " + id;
to :-
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = '" + id + "'";
Additional
However, there are SQLiteDatabase convenience methods that simplify building queries which also enclose/convert data accordingly.
One of these is the query method (as used in the following).
Rather than
moving to the first row and then
checking to see if you are then at the last row and then
using a moveToNext then going back to 2
in a do while loop, as all of the Cursor move??? methods return
true if the move could be made
otherwise false
you can simplify matters using :-
while(yourcursor.moveToNext) {
.... process the current row
}
As such the following methods could be considered
Note the 2 at the end of the method name is just to distinguish them from the originals
:-
public String dbRawSearch2(String id) {
StringBuilder dbString = new StringBuilder();
String whereclause = "CODART_BARCODE=?";
String[] whereargs = new String[]{id};
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.query(TABLE_CODART,null,whereclause,whereargs,null,null,null);
while (c.moveToNext()) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.close(); //<<<< Should always close cursors when finished with them
db.close();
return dbString.toString();
}
public String dbRawArticoli2(String id) {
StringBuilder dbString = new StringBuilder();
String whereclause = "CODART_ART=?";
String[] whereargs = new String[]{id};
SQLiteDatabase db = this.getWritableDatabase();
Cursor c= db.query(TABLE_ART,null,whereclause,whereargs,null,null,null);
while (c.moveToNext()) {
dbString.append(c.getString(c.getColumnIndex("DESCR_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PVEN_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PACQ_ART"))).append("\n");
}
c.close();
db.close();
return dbString.toString();
}
you should use wether your cursor is null or not and its size
if (c != null) {
if (c.getCount() > 0) {
return "your string";
}
}
return "";// In case no record found
In blank case give proper msg to the end user.
Change this part :
//Move to the first row in your results
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
To :
//Move to the first row in your results
if(c!= null && c.moveToFirst())
{
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
}
Explanation: In the case where there is no same data available you don't have the result set to get the string or column index from the result set.
I am trying to find the most efficient logic for the next situation.
I want to implement on my Android app storing in sql most used functions/actions by users.
dbase structure:
| _id | act_name (text unique) | counter (integer) |
code: (src https://stackoverflow.com/a/20568176/8006698)
int rowID = (int) db.insertWithOnConflict(TABLE_NAME, null, cv,SQLiteDatabase.CONFLICT_IGNORE);
if (rowID != -1){
myLog("Written to base with id = " + rowID);
} else {
db.execSQL("UPDATE stats SET counter=counter + 1 WHERE act_name = '" + mAction+"'");
myLog("stats updated");
}
I was surprised, that 'execSQL' doesn't return value as 'update' method.
I would use:
int rowID = db.update(...);
if (rowID == 0) {
//if not updated then insert
long insertedID = db.insert(...);
myLog("Inserted to base ");
} else
myLog("base updated");
but can't increase here count directly as 'counter=counter + 1' so I've to use 'insertWithOnConflict'.
I'm not sure, is it good practice to use it. Waiting for your ideas.
Replace this
db.execSQL("UPDATE stats SET counter=counter + 1 WHERE act_name = '" + mAction+"'");
Use this
ContentValues values=new ContentValues();
values.put("counter",1)
int rowCount=db.update("stats",values,"act_name=?",new String[]{mAction});
you get update count and do whatever you want.
I have the following code...
protected long getNumQueuedChunks(boolean distinctEntries) throws Exception {
SQLiteDatabase db = null;
try {
db = dbhelper.getReadableDatabase();
String whereClause = C_STATUS + " = ? AND " + C_NUM_FAILURES + " < ?";
String[] whereArgs = new String[] {STATUS_AWAITING_PROCESSING, 10};
long count = DatabaseUtils.queryNumEntries(db, QUEUE_TABLE_NAME, whereClause, whereArgs);
return count;
}
finally {
try {
db.close();
}
catch(Exception ignore) {
}
}
}
...which works fine if I want to return the total amount of rows that match the WHERE condition.
However, I would like to only count records that have distinct/unique combinations of data across these 3 columns: C_URI, C_BYTE_START_NUM and C_NUM_BYTES.
I know I could do something like...
String[] columns = {C_URI, C_BYTE_START_NUM, C_NUM_BYTES};
String whereClause = C_STATUS + " = ? AND " + C_NUM_FAILURES + " < ?";
String[] whereArgs = new String[] {STATUS_AWAITING_PROCESSING, "10"};
Cursor c = db.query(true, QUEUE_TABLE_NAME, columns, whereClause, whereArgs, null, null, null, null);
int count = c.getCount();
...but I am hoping there is a more efficient way to perform a distinct count in this situation??
Just to add clarity, if I have this data in my table...
C_URI | C_BYTE_START_NUM | C_NUM_BYTES
1.jpg | 0 | 1024
1.jpg | 1024 | 1999
2.jpg | 0 | 500
2.jpg | 0 | 500
...the result of the distinct count should be 3.
NB - I have seen a similar requirement described here (second answer) but that doesn't help me as I am wanting to do a distinct count across 3 columns rather than just one.
The most efficient way of counting records is to let the database do this:
SELECT COUNT(*)
FROM (SELECT DISTINCT Uri,
ByteStartNum,
NumBytes
FROM QueueTable)
(With the separate subquery, it does not matter if you use DISTINCT or GROUP BY over the three columns.)
This query does not fit into the constraints of one of the helper functions like query or queryNumEntries, so you have to construct the entire SQL statement by hand:
long getNumQueuedChunks() {
SQLiteDatabase db = dbhelper.getReadableDatabase();
try {
String query = "SELECT COUNT(*) FROM " +
"(SELECT DISTINCT " + C_URI + "," + C_BYTE_START_NUM + "," + C_NUM_BYTES +
" FROM " + QUEUE_TABLE_NAME +
" WHERE " + C_STATUS + " = ?" +
" AND " + C_NUM_FAILURES + " < 10)";
String[] args = new String[] { STATUS_AWAITING_PROCESSING };
return DatabaseUtils.longForQuery(db, query, args);
} finally {
db.close();
}
}
Have you tried the SQLiteDatabase.rawQuery() method? You can put a raw SQL query in it, for example, something like:
select distinct C_URI, C_BYTE_START_NUM, C_NUM_BYTES from MyTable
The method returns a Cursor, and you can immediately get the count from the cursor object. Of course, you can specify a where clause if you want to as well. Then free up the Cursor once you got your count.
I try to insert into a database some values(message body and date) only if the phone number (number) doesn't exist in it, but my code doesn't working. Can you give some advice?
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+") SELECT "+number+" WHERE NOT EXISTS "
+ "(SELECT 1 FROM version2 WHERE number = "+number+")", null);
if (cursor.moveToFirst()) {
do {
} while (cursor.moveToNext());
}
}
Try this query.
Seems like your select query is incorrect while insert record.
INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+") WHERE number IS NOT NULL or number <> '';
You need to create a method which will check for the duplicate phone number.
private boolean isPhoneExists ( long number )
{
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select phone from version2 where number = " + number, null );
if (cursor.getCount() > 0)
return true;
else
return false;
}
//Now your inserting statement
if ( !isPhoneExists ( "987654321" ) )
{
Cursor cursor = db.rawQuery("INSERT INTO version2 (number, body, date) values ("+number+","+body+","+ date+")
....
}
I am trying to get the last 3 entries made to the database. Im using the following code but im only getting the last entry not the last 3.
String query = "Select * from " + TABLE_DETAILS + " DESC limit 3;";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
cursor.moveToFirst();
System.out.println(Integer.parseInt(cursor.getString(2)));
cursor.close();
} else {
}
db.close();
Thanks
You'll need to loop with the cursor to get all result rows, e.g. instead of
if (cursor.moveToFirst()) {
...
loop like this
while (cursor.moveToNext()) {
System.out.println(cursor.getString(2));
}
cursor.close();
To change the ordering, add ORDER BY <expression> to your query, for example
SELECT ... ORDER BY _id DESC LIMIT 3