Column not created in SQLITE3 table - android

Now I have a weird problem, I've done all kinds of test and I believe I'm seeing something weird.
I create three tables in SQLiteOpenHelper:
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL(TABLE_CHANNELS_CREATE);
db.execSQL(TABLE_FEEDS_CREATE);
db.execSQL(TABLE_FEEDMAP_CREATE);
}
catch (SQLiteException e){
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
The CREATE statements for the three tables follow:
CREATE TABLE IF NOT EXISTS IRChannels (
ChannelId INTEGER PRIMARY KEY,
ChannelHash TEXT NOT NULL,
ChannelTitle TEXT NOT NULL,
ChannelDesc TEXT, ChannelLink TEXT);
CREATE TABLE IF NOT EXISTS IRFeeds (
FeedId INTEGER PRIMARY KEY,
FeedHash TEXT NOT NULL,
FeedTitle TEXT NOT NULL,
FeedDescription TEXT,
FeedLink TEXT);
CREATE TABLE IF NOT EXISTS IRFeedMap (
ChannelHash_FK TEXT NOT NULL,
FeedHash_FK TEXT NOT NULL,
FOREIGN KEY (ChannelHash_FK) REFERENCES IRChannels (ChannelHash),
FOREIGN KEY (FeedHash_FK) REFERENCES IRFeeds (FeedHash));
The problem is apparently the column FeedHash in IRFeeds is not created while others are. I'm looking at the output in sqlite3 command prompt;
sqlite> .schema
CREATE TABLE IRChannels (
ChannelId INTEGER PRIMARY KEY,
ChannelHash TEXT NOT NULL,
ChannelTitle TEXT NOT NULL,
ChannelDesc TEXT,
ChannelLink TEXT);
CREATE TABLE IRFeedMap (
ChannelHash_FK TEXT NOT NULL,
FeedHash_FK TEXT NOT NULL,
FOREIGN KEY (ChannelHash_FK) REFERENCES IRChannels (ChannelHash),
FOREIGN KEY (FeedHash_FK) REFERENCES IRFeeds (FeedHash));
CREATE TABLE IRFeeds (
FeedId INTEGER PRIMARY KEY,
FeedHash TEXT NOT NULL,
FeedTitle TEXT NOT NULL,
FeedDescription TEXT,
FeedLink TEXT);
This does list the FeedHash column in IRFeeds. However, when I execute
sqlite> select * from IRFeeds where FeedHash='';
SQL error: no such column: FeedHash
All other columns do not give such errors. This condition is causing my code to fail unexpectedly as well. What could I be missing?
sqlite> select * from IRFeeds where FeedID=1;
sqlite> select * from IRFeeds where FeedTitle='';
sqlite> select * from IRFeeds where FeedDescription='';
sqlite> select * from IRFeeds where FeedLink='';
No errors above when I execute select statement for other columns.

There is no error in your SQL. I tested and everything was created properly. Also your SQL query did not cause no such column error. So try to delete the database with context.deleteDatabase(databaseName); and try again.

After an entire day of struggle, I managed to isolate why the problem triggers. Still don't know why, but it does fix the problem. The problems occurs because of the following table which has foreign keys on the other two tables:
CREATE TABLE IRFeedMap (
ChannelHash_FK TEXT NOT NULL,
FeedHash_FK TEXT NOT NULL,
FOREIGN KEY (ChannelHash_FK) REFERENCES IRChannels (ChannelHash),
FOREIGN KEY (FeedHash_FK) REFERENCES IRFeeds (FeedHash));
Changing the column names of foreign key columns to be the same as the column they reference fixes the problem. I changed the statement above to:
CREATE TABLE IRFeedMap (
ChannelHash TEXT NOT NULL,
FeedHash TEXT NOT NULL,
FOREIGN KEY (ChannelHash) REFERENCES IRChannels (ChannelHash),
FOREIGN KEY (FeedHash) REFERENCES IRFeeds (FeedHash));
And voila! Sanity was restored. Beats me.

In my case I was using a SQLite reserved word (column, that was)
I ended up in this SO question, so maybe it helps others in my situation

Related

NOT NULL constraint failed while copying data to a new table

I migrate my database from SQLiteOpenHelper to Room.
I have a table that I want to change, lets call it "my_table".
Its simplified create statement:
CREATE TABLE `my_table`
(`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`title` TEXT
)
During an upgrade among other changes I add the new column type INTEGER NOT NULL (I'm adding Foreign Key aswell and doing other significant changes, that's the reason to create a new table instead of altering the existing one):
CREATE TABLE "new_table"
(`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`title` TEXT,
`type` INTEGER NOT NULL
)
Then I want to copy data from the my_table to the new_table and set type column's values.
SQL statement:
INSERT INTO new_table (title)
SELECT title FROM my_table;
UPDATE new_table SET type = 1;
DROP TABLE my_table;
ALTER TABLE new_table RENAME TO my_table;
Android migration:
public static final Migration MIGRATION_TEST = new Migration(1, 2) {
#Override
public void migrate(#NonNull SupportSQLiteDatabase database) {
// Create new table
database.execSQL("CREATE TABLE new_table (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `type` INTEGER NOT NULL)");
// Copy some data
database.execSQL("INSERT INTO new_table (title) SELECT title FROM old_table"); // constraint violation
// Insert default value into the measures column
database.execSQL("UPDATE new_table SET type = 1");
// Delete old table
database.execSQL("DROP TABLE old_table");
// Rename new table
database.execSQL("ALTER TABLE new_table RENAME TO my_table");
}
};
Obviously I get NOT NULL constraint failed: new_table.type error:
android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: new_table.type (code 1299)
Error Code : 1299 (SQLITE_CONSTRAINT_NOTNULL)
Caused By : Abort due to constraint violation.
(NOT NULL constraint failed: new_table.type (code 1299))
I can avoid it by changing new table's create statement and setting default value for the type column.
CREATE TABLE "new_table"
(`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`title` TEXT,
`type` INTEGER NOT NULL DEFAULT 1
)
But I don't want to do this as Room doesn't suport default values out of the box and in order to avoid future mistakes when inserting new values into tables.
Are there any workarounds to avoid this error while inserting data to a new table?
I think the following may work :-
database.execSQL("INSERT INTO new_table (title,type) SELECT title, 1 FROM old_table");
That is, you are now saying to INSERT 2 columns as per the SELECT statement. The SELECT returns 2 values the title from the old_table and the literal value 1.
That is SELECT actual returns the result of expressions result-column which aren't limited to just columns. An Expression can be literal value, result of functions, results of operations and other expr
As per
The list of expressions between the SELECT and FROM keywords is known
as the result expression list.
SQL As Understood By SQLite - SELECT - 3. Generation of the set of result rows.
You then wouldn't need database.execSQL("UPDATE new_table SET type = 1").

Can't find the syntax error in this SQLite statement

I am writing an Android app and need a database for it. I will have three tables but only managed to make one right now. I do them in the console to debug and to implement them in my Javacode later. The following statements were succesfull:
sqlite3 progressapp.db
CREATE TABLE Z_Type(_Z_T_ID INTEGER PRIMARY KEY NOT NULL,
Description TEXT NOT NULL, Unit TEXT NOT NULL);
But now I want to refference the PK of T_Type in my other table:
CREATE TABLE goals (_Z_id INTEGER PRIMARY KEY NOT NULL, Title TEXT NOT NULL,
Type INTEGER NOT NULL, FOREIGN KEY(Type) REFERENCES Z_Type(_Z_T_ID),
Timeframe TEXT, Goaldate INTEGER);
Is Type INTEGER NOT NULL, FOREIGN KEY(Type) REFERENCES Z_Type(_Z_T_ID) a valid SQLite Statement in Android? It says "Error: near "Timeframe": syntax error" But I simply can't find it due to lack with SQL Experience I guess.
Is there a better way to reference the FK maybe?
Try this:
CREATE TABLE goals (_Z_id INTEGER PRIMARY KEY NOT NULL, Title TEXT NOT NULL,
Type INTEGER NOT NULL,Timeframe TEXT, Goaldate INTEGER, FOREIGN KEY(Type) REFERENCES Z_Type(_Z_T_ID));
I think that the order is important.
For further documentation you could visit sqlite.org/foreignkeys.html
You can define the reference as part of the column definition
CREATE TABLE goals (_Z_id INTEGER PRIMARY KEY NOT NULL, Title TEXT NOT NULL,
Type INTEGER NOT NULL REFERENCES Z_Type(_Z_T_ID),
Timeframe TEXT, Goaldate INTEGER);
In a sqlite CREATE TABLE statement, column definitions come first and table constraints only after that.
FOREIGN KEY(Type) REFERENCES Z_Type(_Z_T_ID) is a table constraint that should go at the end.

Foreign Key Android DATABASE

I'm confused about the correct usage and implementation of the "Foreign KEY" in the SQLite Database in Android.
I created a DB with several relations, as following:
CREATE TABLE "food" (
`_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`name` TEXT NOT NULL,
`description` TEXT,
`category_id` INTEGER,
FOREIGN KEY(`category_id`) REFERENCES food(_id) )
CREATE TABLE `category` (
`_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`cagory_name` TEXT NOT NULL)
CREATE TABLE "favourites" (
`_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`id_favourite` INTEGER NOT NULL,
FOREIGN KEY(`id_favourite`) REFERENCES food ( _id ))
As you can see, there are 3 tables and the _id of "food" is the foreign key connecting the table "category" and "favourites".
Now, in Android I don't see happening ANYTHING that proves that I created such a relation among tables. Do I miss some declaration to make it effective?
How does it work in Android?
The category_id foreign key reference seems odd.
Is there a reason it's:
FOREIGN KEY(`category_id`) REFERENCES food(_id)
and not
FOREIGN KEY(`category_id`) REFERENCES category(_id)
To make sure foreign key constraints are enforced, in SQLite run
PRAGMA foreign_keys = ON;
See http://www.sqlite.org/foreignkeys.html for documentation.

creating android db table

I am new on android. I am trying to create a table in a db using the following code but there is some error
db.beginTransaction();
try {
db.execSQL("CREATE TABLE IF NOT EXISTS `book` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(100) NOT NULL,`author_name` varchar(100) NOT NULL,`text_b` text NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;");
db.setTransactionSuccessful();
} catch (SQLiteException e) {
Log.d("Maaz", "Exception 2 : SQL Exception 2 " + e.getMessage());
} finally {
db.endTransaction();
}
The above code is giving me the following error
Failure 1 (near "AUTO_INCREMENT": syntax error)
on 0x23c510 when preparing 'CREATE TABLE IF NOT EXISTS `book` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(100) NOT NULL,`author_name` varchar(100) NOT NULL,`text_b` text NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;'.
Kindly help me. Thanks in advance.
Change AUTO_INCREMENT to AUTOINCREMENT.
Edit:
Try this,
CREATE TABLE IF NOT EXISTS book (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
title varchar(100) NOT NULL,
author_name varchar(100) NOT NULL,
text_b TEXT NOT NULL
);
This Worked at last in my case.
Answer :
CREATE TABLE IF NOT EXISTS book (
_id Integer PRIMARY KEY AUTOINCREMENT,
title varchar(100) NOT NULL,
author_name varchar(100) NOT NULL,
text_b TEXT NOT NULL);
Removing Engine, DEFAULT CHARSET worked for me
what kind of database, it makes a difference for the SQL syntax. You should try to create the database table first in the console editor and then you can paste that syntax in your code. It's also usually not a good idea to create tables from code with a generic execSQL. You should use an ORM or database library or framework for this. A continuous integration server could also create this table unless your are creating it on the client's android device. Hibernate is nice for keeping messy SQL out of your code.
Can you tell us what kind of database?
You can also check out this article:
http://androidforbeginners.blogspot.com/2010/01/creating-multiple-sqlite-database.html
Very close syntax if you are using SQLite
It seems you have quotes surrounding the identifiers (I.e. books). Remove them.

Why is SQLiteOpenHelper recreating my existing database?

I'm trying to push a database to the emulator. I created the database with a script on my desktop computer, it looks the same as the database created by my SQLiteOpenHelper subclass:
CREATE TABLE android_metadata (locale TEXT);
insert into android_metadata values('en_US');
CREATE TABLE notes (_id integer primary key autoincrement,
key text,
content text not null,
modifydate text,
createdate text,
syncnum integer,
version integer,
minversion integer,
sharekey text,
publishkey text,
deleted integer not null default 0,
pinned integer not null default 0,
unread integer not null default 0);
CREATE TABLE tags (_id integer primary key autoincrement,
name text not null,
pos integer not null,
noteid integer not null,
foreign key(noteid) references notes (_id));
But for some reason the app tries to recreate the database even though it already exists. It fails when it tries to create a table that already exists in the database. Maybe someone here knows why?
OK. It turns out that I need to set the version on the database to the same version that my code expects. This is done in my sqlite script like so:
PRAGMA user_version = 1;

Categories

Resources