I am having trouble getting a foreign key to update in a SQLite table that's running in my Android app.
I have two tables, CASHFLOW_TABLE and ACCOUNT_TABLE. CASHFLOW_TABLE has a foreign key column that references the _id column of ACCOUNT_TABLE. I want to update values in one line of CASHFLOW_TABLE, but when I run this code
String where = "_id=?";
String[] whereArgs = {"7"};
ContentValues cv = new ContentValues();
cv.put(CF_COL_PURPOSE, "Coffee");
cv.put(CF_COL_VALUE, 2.5);
cv.put(CF_COL_ACCOUNT_ID, 4);
myDatabase.update(CF_TABLE_NAME, cv, where, whereArgs);
I receive the error message:
E/Database(22962): Error updating ACCOUNT_ID=4 VALUE=2.5 PURPOSE=Coffee using UPDATE CASHFLOW_TABLE SET ACCOUNT_ID=?, VALUE=?, PURPOSE=? WHERE _id=?
The reason I think this has something to do with the fact that CF_COL_ACCOUNT_ID is a foreign key is that when I remove
cv.put(CF_COL_ACCOUNT_ID, 4);
and run the code just to update just the other values, it works fine. Any ideas what I am doing wrong?
Update: when I try to run the update as an SQL statement, I get the following error, which does seem to suggest that the problem is with the foreign key constraint:
E/Database(24650): Failure 19 (foreign key constraint failed) on 0x314530 when executing 'update CASHFLOW_TABLE set VALUE= 2.5, PURPOSE='coffee', ACCOUNT_ID=4 where _id = 7'
Below is the code in onCreate() that sets up the tables and foreign key constraint. I have simplified it a bit here--there are other columns and one other foreign key (for a third table not shown here).
db.execSQL("Create table " + A_TABLE_NAME + " (" + A_COL_ID + " integer primary key autoincrement, " + A_COL_NAME
+ " text default ('" + A_DEFAULT_ACCOUNT + "'));");
db.execSQL("Create table " + CF_TABLE_NAME + " (" + CF_COL_ID
+ " integer primary key autoincrement, " + CF_COL_VALUE
+ " real not null, "
+ CF_COL_PURPOSE + " text not null, " + CF_COL_TIMESTAMP
+ " text not null default (strftime('%s','now')), "
+ CF_COL_ACCOUNT_ID
+ " integer not null default 1, foreign key ("
+ CF_COL_ACCOUNT_ID + ") references " + A_TABLE_NAME + " ("
+ A_COL_ID + ") on delete set default);");
Related
can anyone work out what is wrong with this code? I'm getting cannot resolve error and both foreign key and references are in red.
private static final String CREATE_TABLE_EXPENSES = "CREATE TABLE " + TABLE_EXPENSES
+ " (" + COL_ID + " INTEGER PRIMARY KEY," + COL_EXPENSES_SOURCE + " TEXT,"
+ COL_EXPENSES_AMOUNT + "NUMERIC," + COL_DATE + "DATE," + COL_DESCRIPTION + "TEXT," +
COL_FOREIGN_KEY_CATEGORY + " INTEGER, "+ FOREIGN_KEY ("+COL_FOREIGN_KEY_CATEGORY+")
REFERENCES "+DatabaseManager.TABLE_CATEGORY+"("+COL_ID+"));";
The answer was purely about adding spaces between some of the + and attributes.
I know this question has been asked multiple times, but there is something wrong in my syntax and I can't figure out what. This is the method that adds my column:
Property declaration:
public static final String COLUMN_TS_MILIS = "ts_milis";
public void onCreate(SQLiteDatabase db) {
String query = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_PRODUCT + " TEXT, " +
COLUMN_PRICE + " TEXT, " +
COLUMN_TS + " TIMESTAMP DEFAULT CURRENT_TIMESTAMP," +
COLUMN_TS_MILIS + "timestamp integer default (cast(strftime('%s', 'now') as int))" +
");";
db.execSQL(query);
and this is the query that triggers the error:
Cursor totalCof = db.rawQuery("SELECT sum(" + COLUMN_PRICE + ")" + " FROM " + TABLE_NAME
+ " WHERE " + COLUMN_TS_MILIS + "= date('now')", null);
What is wrong in my syntax? Many thanks for help!
For the column that is meant to be named as per COLUMN_TS_MILIS, have omitted a space between the column name and the column type and hence the column name is a concatenation of the column name and column type. So assuming COLUMN_TS_MILIS resolves to millis then the QL will be :-
`CREATE TABLE ......,millistimestamp integer default (cast(strftime('%s', 'now') as int))`
instead of
`CREATE TABLE ......,millis timestamp integer default (cast(strftime('%s', 'now') as int))`
Additionally you have specified two types, timestamp and also integer, this won't be an issue SQLIite wise but may lead to confusion.
As such you probably just want
`CREATE TABLE ......,millis integer default (cast(strftime('%s', 'now') as int))`
As such you probably want to use :-
String query = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY, " +
COLUMN_PRODUCT + " TEXT, " +
COLUMN_PRICE + " TEXT, " +
COLUMN_TS + " TIMESTAMP DEFAULT CURRENT_TIMESTAMP," +
COLUMN_TS_MILIS + " INTEGER DEFAULT (cast(strftime('%s', 'now') as int))" +
");";
Note AUTOINCREMENT has been removed as you almost certainly don't need it as it has overheads.
To implement the change, you would have to drop the table, as it exists. The easiest way to do this is to either :-
delete the App's data or
uninstall the App
and then rerun the App (assuming that existing, if any, data can be lost).
I'm receiving the following error from my insert db call.
"android.database.sqlite.SQLiteException: near "t": syntax error (code 1): , while compiling: INSERT INTO OCR(bmp, title, description) VALUES ('[B#9430d52', 'Result:', '
pacifism
Enchant creature
Creature can't attack Or
That
—Knrtce of Qal Sima
');
This is my insert statement
String INSERT_TO_DB = "INSERT INTO " + TABLE_NAME + " ("+
COLUMN_BITMAP + ", " +
COLUMN_TITLE + ", " +
COLUMN_DESCRIPTION +") " +
"VALUES ('" + getBytes(ocr.getBitmap()) + "', '" + ocr.getTitle() + "', '" + ocr.getDescription() + "');";
db.execSQL(INSERT_TO_DB);
The thing is it was working on other images, i'm thinking it has something to do with the fact that there's a lot of "/n" in the description it's trying to insert into the db.
Never put string values directly into an SQL statement; use parameters instead.
It is not necessary to use a prepared statement object to achieve this:
db.execSQL("INSERT ... VALUES(?, ?, ?)",
new Object[]{ ocr.getTitle(), ... });
And there is a helper function that constructs the statement for you, and handles binary data correctly:
ContentValues cv = new ContentValues();
cv.put(COLUMN_TITLE, ocr.getTitle());
cv.put(COLUMN_BITMAP, ocr.getBitmap()); // byte array
...
db.insert(TABLE_NAME, null, cv);
This is my create table statement.
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_BRANDS + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_CREATED_AT + " TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ KEY_UPDATED_AT + " TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" + ")";
as per SQLITE document ON UPDATE CURRENT_TIMESTAMP is not allowed in column definition.
so i thought of passing KEY_UPDATED_AT values while updating a row.
This is my update function.
public int updateBrand(Brand brand) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, brand.getName());
values.put(KEY_UPDATED_AT, ?????)
// updating row
return db.update(TABLE_BRANDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(brand.getId()) });
}
My question is what values should i put values.put(KEY_UPDATED_AT, ?????), to update the row properly.
The ContentValues object allows only literal values.
To do any kind of computation, you must use execSQL instead:
db.execSQL("UPDATE "+TABLE_BRANDS+
" SET "+KEY_NAME+" = ?, "+
KEY_UPDATED_AT+" = CURRENT_TIMESTAMP"+
" WHERE "+KEY_ID+" = ?",
new Object[]{ brand.getName(), brand.getId() });
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID + " INTEGER PRIMARY KEY
AUTOINCREMENT, KEY_PNAME + " TEXT NOT NULL, " + KEY_LOC + " TEXT NOT NULL, "
+ KEY_TH + " TEXT NOT NULL);"
Now suppose I have to extract the value of KEY_ROWID of a particular value of KEY_LOC.then what query should I fire on database because in my app if I have a location's latitude longtitude(KEY_LOC). I should be able to show rest of the data associated with that location.