Android SQLite : constraint failed error code 19 - java

I have execute the following sql:
update record set out_payment=4 where out_payment=4;
the out_payment of record is defined as Integer and reference the Payment(id)
I can ensure the 4 was the one of the ID of the payment table;
but I still got the constrained failed....
07-31 10:20:36.014: ERROR/Database(19085): Error updating out_payment=4 using UPDATE record_table SET out_payment=? WHERE out_payment = 4
07-31 10:20:45.964: ERROR/AndroidRuntime(19085): FATAL EXCEPTION: main
07-31 10:20:45.964: ERROR/AndroidRuntime(19085): android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
the code is as following:
values.clear();
values.put(RecordSchema.ID_OUT_PAYMENT, oldid);
selection = RecordSchema.ID_OUT_PAYMENT + " = " + oldid + "";
this.db.update(Table.RECORD, values, selection, null);
the Schema is as following :
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE.RECORD
+ " (" + RecordSchema.ID + " INTEGER PRIMARY KEY"
+ "," + RecordSchema.AMOUNT + " TEXT NOT NULL"
+ "," + RecordSchema.ID_CATEGORY + " INTEGER NOT NULL"
+ "," + RecordSchema.ID_SUBCATEGORY + " INTEGER"
+ "," + RecordSchema.DATE + " DATE NOT NULL"
+ "," + RecordSchema.ID_IN_PAYMENT + " INTEGER"
+ "," + RecordSchema.ID_OUT_PAYMENT + " INTEGER"
+ ",FOREIGN KEY(" + RecordSchema.ID_CATEGORY + ") REFERENCES "
+ IsAiZanTable.CATEGORY + "(" + CategorySchema.ID + ") ON UPDATE CASCADE"
+ ",FOREIGN KEY(" + RecordSchema.ID_SUBCATEGORY + ") REFERENCES "
+ IsAiZanTable.SUBCATEGORY + "(" + SubcategorySchema.ID + ") ON UPDATE CASCADE"
+ ",FOREIGN KEY(" + RecordSchema.ID_IN_PAYMENT + ") REFERENCES "
+ IsAiZanTable.PAYMENT + "(" + PaymentSchema.ID + ") ON UPDATE CASCADE"
+ ",FOREIGN KEY(" + RecordSchema.ID_OUT_PAYMENT + ") REFERENCES "
+ IsAiZanTable.PAYMENT + "(" + PaymentSchema.ID + ") ON UPDATE CASCADE"
+ ");");
db.execSQL("CREATE TABLE IF NOT EXISTS " +Table.PAYMENT
+ " (" + PaymentSchema.ID + " INTEGER PRIMARY KEY"
+ "," + PaymentSchema.KIND + " INTEGER NOT NULL"
+ "," + PaymentSchema.NAME + " TEXT NOT NULL UNIQUE"
+ "," + PaymentSchema.TOTAL + " TEXT NOT NULL"
+ "," + PaymentSchema.HIDDEN + " INTEGER NOT NULL"
+ ");");
Any body can help me to solve this problem?
Actually I want to update the id from 4 to 5
I can ensure both 4 and 5 are the exist IDs of the payment table.
But the same problem occurred, so I update 4 to 4 is the same.
I think if I can solve the problem of 4 to 4 , I should solve the problem of 4 to 5 .
Many thanks for your answer!!

I have found the answer.
One of my team run the following
db.execSQL("PRAGMA foreign_keys = OFF;");
then put the 0 into the ID_OUT_PAYMENT of record table .
The 0 is not the exist id of the PAYMENT table.
So when I update the ID_OUT_PAYMENT it will trigger the constraint failed.
So If I want to make my sql above run successfully.
I need to run the sql too.
db.execSQL("PRAGMA foreign_keys = OFF;");
Thanks very much for every one to reply me!!
Thanks!

Related

From Javafile to SQL query - Minecraft plugin

as i am working on a minecraft server some plugin does not make a certain table itself.
For who is interested: https://www.spigotmc.org/resources/craftconomy.2395/
But in the github files i found the java script where it does generate the needed table.
public final String createTableMySQL = "CREATE TABLE IF NOT EXISTS " + getPrefix() + TABLE_NAME + " (" +
" `" + BALANCE_FIELD + "` double DEFAULT NULL," +
" `" + WORLD_NAME_FIELD + "` varchar(255)," +
" `username_id` int(11)," +
" `" + CURRENCY_FIELD + "` varchar(50)," +
" PRIMARY KEY (" + WORLD_NAME_FIELD + ", username_id, currency_id)," +
" CONSTRAINT `"+getPrefix()+"fk_balance_account`" +
" FOREIGN KEY (username_id)" +
" REFERENCES " + getPrefix() + AccountTable.TABLE_NAME + "(id) ON UPDATE CASCADE ON DELETE CASCADE," +
" CONSTRAINT `"+getPrefix()+"fk_balance_currency`" +
" FOREIGN KEY (" + CURRENCY_FIELD + ")" +
" REFERENCES " + getPrefix() + CurrencyTable.TABLE_NAME +"(name) ON UPDATE CASCADE ON DELETE CASCADE" +
") ENGINE=InnoDB CHARSET=utf8;";
Could someone help me to make a SQL query out of this, which just can be dropped into PHPMyadmin?
Thanks already for reading.
I already solved it myself, no reason for reaction anymore.

problem while using database column value into Date() sqlite android

i have small problem, i googled it many times but i couldn't get it...
i'm using a query (sqlite) to retrieve some data ..
in this query their is Date() used to increase certain date dynamic number of days (coming from column in the same table) ..
if i put this days static (1,2,3,.....) it works fine but if i put column name it doesn't.
this query fails and i want it to work:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "',' " + REPETITIONS + " day') ";
this works fine :
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "','2 day') ";
where
targetDate: date entered by user to get events of that date
DATE: date of every event in the table
REPETETIONS: dynamic number (column in the same table)
the problem is using REPETITIONS in the date function...
create statement
String SQL_CREATE_EVENT_TABLE = "CREATE TABLE " + TABLE_NAME + " ( " +
ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
TITLE + " TEXT ," +
DATE + " TEXT , " +
IS_NOTIFY + " INTEGER , " +
NOTIFICATION_TIME + " TEXT ," +
REPEAT + " INTEGER ," +
REPEAT_DURATION + " INTEGER ," +
REPETITIONS + " INTEGER ," +
CERTAIN_DATE + " TEXT ," +
NOTE + " TEXT ," +
IS_SPOKEN + " INTEGER " +
" );";
and this is the selecting statement
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE " + DATE + " = '" + targetDate
+ "' OR (( " + REPEAT + " = '1' AND " + REPEAT_DURATION + " = '0' ) AND " + DATE + " <= '" + targetDate + "')"
+ " OR( " + REPEAT + " = '1' AND " + REPEAT_DURATION + " = '3' ) AND " + DATE + " <= '" + targetDate + "' AND " + CERTAIN_DATE + " >= '" + targetDate + "'"
+ " OR (" + REPEAT + " = '1' AND " + REPEAT_DURATION + "= '2' ) AND " + targetDate + " >= '" + DATE + "' AND "+ targetDate+ " <= date('" + DATE + "','" + REPETITIONS + " days')";
The variable REPETITIONS in this statement:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "',' " + REPETITIONS + " day') ";
should be a number and not a column name.
The date function in SQLite has various syntaxes but you use this one:
SELECT date('2014-10-23','+7 day');
you must supply a number before day.
Edit try this:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "', " + REPETITIONS + " || ' day') ";
In sqlite date() function, the NNN days is a string modifier and not an expression. Therefore you cannot use column names or even || string concatenation there.
You can format the modifier string in your code and place it in the SQL. This requires additional query to the database, which is likely not what you want.
If you can assume each day is 24 hours (which is not always true, consider e.g. DST events), you could try something like
... date(strftime('%s', '" + targetDate + "', " + REPETITIONS + "*24*60*60, 'unixepoch') ...
where strftime('%s', ...) converts to seconds and date(..., 'unixepoch') converts back to datestamp.
But seriously I'd consider redesigning the schema to better support your functional requirements.

Syntax to create unique composite column - Android SQLiteOpenHelper

I have this onCreate method in my SQLiteOpenHelper
class, and I would like to add a unique constraint on these two columns (composite unique columns):
SongContract.SongEntry.COLUMN_TITLE
SongContract.SongEntry.COLUMN_RELEASEDATE
But I am getting an error:
Cannot resolve method UNIQUE
Here is my code:
public void onCreate(SQLiteDatabase db) {
final String SQL_CREATE_SONG_TABLE = "CREATE TABLE " + SongContract.SongEntry.TABLE_SONG + " (" +
SongContract.SongEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
SongContract.SongEntry.COLUMN_TITLE + " TEXT NOT NULL, " +
SongContract.SongEntry.COLUMN_RELEASEDATE + " INTEGER, " +
UNIQUE(SongContract.SongEntry.COLUMN_TITLE, SongContract.SongEntry.COLUMN_RELEASEDATE) +
SongContract.SongEntry.COLUMN_RATING + " TEXT);";
db.execSQL(SQL_CREATE_SONG_TABLE);
}
What is the correct syntax to achieve my goal?
I found the corrrect syntax after playing around sqllite:
final String SQL_CREATE_SONG_TABLE = "CREATE TABLE " + SongContract.SongEntry.TABLE_SONG + " (" +
SongContract.SongEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
SongContract.SongEntry.COLUMN_TITLE + " TEXT NOT NULL, " +
SongContract.SongEntry.COLUMN_RELEASEDATE + " INTEGER NOT NULL, " +
SongContract.SongEntry.COLUMN_RATING + " TEXT, " + "UNIQUE" + "(" +
SongContract.SongEntry.COLUMN_TITLE + "," + SongContract.SongEntry.COLUMN_RELEASEDATE + ") " + ");";

onCreate is called as expected. But tables are not created

So I've got this problem which is really annoying me. I override the onCreate method of my class extending SQLiteOpenHelper:
#Override
public void onCreate(SQLiteDatabase db) {
super.onCreate(db);
final String createAccTableCmd = ("CREATE TABLE IF NOT EXISTS " + ACCOUNTS_TABLE_NAME + " ( " +
ACCOUNT_KEY_ID + " INTEGER PRIMARY KEY ASC AUTOINCREMENT, " +
ACCOUNT_KEY_NAME + " TEXT UNIQUE ON CONFLICT IGNORE NOT NULL ON CONFLICT IGNORE, " +
ACCOUNT_KEY_SELECTED + " INTEGER NOT NULL ON CONFLICT IGNORE, " + //THIS IS IN MILLISECONDS
"CHECK (" + ACCOUNT_KEY_SELECTED + " = 0 OR " + ACCOUNT_KEY_SELECTED + " = 1) ON CONFLICT IGNORE" +
" ) ");
final String oneAndOnlyOneSelectedAccInsertTriggerCmd = "CREATE TRIGGER " + ONE_AND_ONLY_ONE_SELECTED_TRIGGER_INSERT_NAME + " " +
"AFTER INSERT ON " + ACCOUNTS_TABLE_NAME + " " +
"FOR EACH ROW " +
"BEGIN " +
"DELETE FROM " + ACCOUNTS_TABLE_NAME + " WHERE " + ACCOUNT_KEY_ID + " = NEW." + ACCOUNT_KEY_ID + "; " +
"END";
final String oneAndOnlyOneSelectedUpdateTriggerCmd = "CREATE TRIGGER " + ONE_AND_ONLY_ONE_SELECTED_TRIGGER_UPDATE_NAME + " " +
"AFTER UPDATE ON " + ACCOUNTS_TABLE_NAME + " " +
"FOR EACH ROW " +
"WHEN (SELECT(SUM(" + ACCOUNT_KEY_ID + ")) <> 1) " +
"BEGIN " +
"UPDATE " + ACCOUNTS_TABLE_NAME + " SET " + ACCOUNT_KEY_SELECTED + " = 0; " +
"UPDATE " + ACCOUNTS_TABLE_NAME + " SET " + ACCOUNT_KEY_SELECTED + " = 1 WHERE " + ACCOUNT_KEY_ID + " = NEW." + ACCOUNT_KEY_ID + "; " +
"END";
synchronized (DB_LOCK) {
db.beginTransaction();
db.execSQL(createAccTableCmd);
db.execSQL(oneAndOnlyOneSelectedAccInsertTriggerCmd);
db.execSQL(oneAndOnlyOneSelectedUpdateTriggerCmd);
addTableName(ACCOUNTS_TABLE_NAME);
ContentValues cv = new ContentValues();
cv.put(ACCOUNT_KEY_ID, 0);
cv.put(ACCOUNT_KEY_NAME, "name");
cv.put(ACCOUNT_KEY_SELECTED, 0);
Log.d("debug", "-1 if error on insert: " + db.insert(ACCOUNTS_TABLE_NAME, "", cv));
Log.d("debug", "Size: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());
db.setTransactionSuccessful();
db.endTransaction();
LBackupAgent.requestBackup(mContext);
}
Log.d("debug", "Size after ending the transaction: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());
}
One would expect the output of this to be:
-1 if error on insert: 0
Size: 0 /* or 1, if the select takes into account the data not committed of the current transaction, I'm not sure about this */
Size after ending the transaction: 1
When the actual output happens to be:
-1 if error on insert: 0
Size: 0
Size after ending the transaction: 0
How can it be that the insertion is successful but the selection returns 0 rows?
I've checked with a shell that the table does exist, but effectively it is empty, which could be explained by the fact that the tables do not seem to be really existing until onCreate() finishes, justifying as well the 0 returned by the insertion command. Should I guess that this some kind of design constraint to make sure that onCreate does only include CREATE TABLE, CREATE TRIGGER and such type of statements? What if I consider that my schema definition needs an insertion (as is the case)?
Try inserting some dummy values instead of below:
ContentValues defaultAcc = mapAccountToStorable(defaultAccDataModel = new AccountListRecyclerAdapter.AccountDataModel(
LBudgetUtils.getInt(mContext, "default_account_id"),
LBudgetUtils
.getString(mContext, "default_account_name"),
mContext.getResources().getBoolean(
R.bool.default_account_selected)));
Instead of sending nullColumnHack as null send it as "". It will make sure that a row will be created in table even if values are null.
db.insert(ACCOUNTS_TABLE_NAME, "", defaultAcc)
Try below:
db.beginTransaction();
db.execSQL(createAccTableCmd);
db.execSQL(oneAndOnlyOneSelectedAccInsertTriggerCmd);
db.execSQL(oneAndOnlyOneSelectedUpdateTriggerCmd);
db.setTransactionSuccessful();
db.endTransaction();
db.beginTransaction();
addTableName(ACCOUNTS_TABLE_NAME);
AccountListRecyclerAdapter.AccountDataModel defaultAccDataModel;
ContentValues defaultAcc = mapAccountToStorable(defaultAccDataModel = new AccountListRecyclerAdapter.AccountDataModel(LBudgetUtils.getInt(mContext, "default_account_id"), LBudgetUtils.getString(mContext, "default_account_name"), mContext.getResources().getBoolean(R.bool.default_account_selected)));
Log.d("debug", "-1 if error on insert: " + db.insert(ACCOUNTS_TABLE_NAME, null, defaultAcc));
db.setTransactionSuccessful();
db.endTransaction();
Log.d("debug", "Size: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());

How correctly address to specific column in Cursor?

Lets assume, that we have some 2 tables in SQLite: TBL_PRODUCT and TBL_PRODUCT_ALIASES. Now, I want to query some data from joined two tables:
String sql = "SELECT " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + ", " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" FROM " + TBL_PRODUCT + " LEFT JOIN " + TBL_PRODUCT_ALIASES + " ON " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + " = " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" WHERE " + C_PROD_SERVER_ID + " = ? LIMIT 1";
Cursor cursor = SQLiteDataHelper.getInstance().rawQuery(sql, new String[] {"" + js_CartProduct.getLong("prod_id")});
Thats works great without any problem. And then I want to acquire some data from the returned cursor:
if (cursor.getCount() > 0) {
cursor.moveToFirst();
Long prodId = cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID));
//... Some other code
}
Now, here is the problem: C_PROD_PKEY_ID and C_PROD_ALIASES_PKEY_ID are in the real world the same Strings: "_id". And as the result getLong() returns long not from the needed column of cursor.
How should I correctly address to the needed column? Are there other methods besides using AS in sql query OR/AND using definite numbers in cursor.getLong(0) instead of cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID))?
Update:
cursor.getColumnNames() returns this: [_id, _id].

Categories

Resources