I have a SQLite database with one table which I need to update in a new version of my database.
In the first version of the table I have a id and a txt value like this:
db.execSQL("CREATE TABLE table_name id INTEGER PRIMARY KEY AUTOINCREMENT, txt TEXT")
But in the next version of the database I wand to add a lastchanged value which must be a TIMESTAMP with default value current time in epoch which I do with (strftime('%s', 'now')).
But since I can't add a column with default current time, according to this error:
Cannot add a column with non-constant default (code 1): , while compiling: ALTER TABLE table_name ADD COLUMN edited_time TIMESTAMP DEFAULT (strftime('%s', 'now'))
I tought I could best recreate the data and copy it to the new database
// copy all data to single value something like a Cursor res maybe??
db.execSQL("DROP TABLE IF EXISTS table_name );
db.execSQL("CREATE TABLE table_name id INTEGER PRIMARY KEY AUTOINCREMENT, txt TEXT, edited_time TIMESTAMP DEFAULT (strftime('%s', 'now'))");
// now insert the values into the recreated database
But for this i need to copy all data into a new table that does not exist simultanious. Is it posible to do this without looping and having to save every value separate and then inserting them seperately again?
Yes. The general procedure is:
BEGIN;
ALTER TABLE table_name RENAME TO table_name_old;
CREATE TABLE table_name( ... );
INSERT INTO table_name(col1, ..., coln)
SELECT col1, ..., coln FROM table_name_old;
DROP table_name_old;
COMMIT;
Related
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").
I have a column with a NOT NULL constraint. I need to alter the database to remove the constraint. But when I try I get a duplicate column exception from android
db.execSQL("ALTER TABLE " + AnimalContract.DogEntry.TABLE_NAME
+ " ADD COLUMN " + AnimalContract.DogEntry.COLUMN_NAME+" TEXT DEFAULT NULL");
I also tried without DEFAULT
The constraint was UNIQUE NOT NULL
There's no direct way to ALTER COLUMN in SQLite.
I believe your only option is to:
Rename the table to a temporary name
Create a new table without the NOT NULL constraint
Copy the content of the old table to the new one
Remove the old table
This other Stackoverflow answer explains the process in details
Furthermore,
MODIFY COLUMN IN TABLE
You can not use the ALTER TABLE statement to modify a column in SQLite. Instead you will need to rename the table, create a new table, and copy the data into the new table.
Syntax
The syntax to MODIFY A COLUMN in a table in SQLite is:
PRAGMA foreign_keys=off;
BEGIN TRANSACTION;
ALTER TABLE table1 RENAME TO _table1_old;
CREATE TABLE table1 (
( column1 datatype [ NULL | NOT NULL ],
column2 datatype [ NULL | NOT NULL ],
...
);
INSERT INTO table1 (column1, column2)
SELECT column1, column2
FROM _table1_old;
COMMIT;
PRAGMA foreign_keys=on;
Example
Let's look at an example that shows how to modify a column in a SQLite table.
For example, if we had an employees table that had a column called last_name that was defined as a CHAR datatype:
CREATE TABLE employees
( employee_id INTEGER PRIMARY KEY AUTOINCREMENT,
last_name CHAR NOT NULL,
first_name VARCHAR,
hire_date DATE
);
And we wanted to change the datatype of the last_name field to VARCHAR, we could do the following:
PRAGMA foreign_keys=off;
BEGIN TRANSACTION;
ALTER TABLE employees RENAME TO _employees_old;
CREATE TABLE employees
( employee_id INTEGER PRIMARY KEY AUTOINCREMENT,
last_name VARCHAR NOT NULL,
first_name VARCHAR,
hire_date DATE
);
INSERT INTO employees (employee_id, last_name, first_name, hire_date)
SELECT employee_id, last_name, first_name, hire_date
FROM _employees_old;
COMMIT;
PRAGMA foreign_keys=on;
This example will rename our existing employees table to _employees_old.
Then it will create the new employees table with the last_name field defined as a VARCHAR datatype. Then it will insert all of the data from the _employees_old table into the employees table.
I created a table called DRINK. I inserted two rows in to it initially. When upgraded, I would like to delete both rows and reset my Primary Key to 1. I am getting the rows to delete but am not having any luck resetting the primary key. Does anybody know the syntax on how to do that or if it's even possible? Here's the function which is called from my onUpdate function:
private void updateMyDatabase(SQLiteDatabase db, int olderVersion, int newVersion){
Log.v("DatabaseHelper","UPDATE MY DATABASE");
if (olderVersion<1){
db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER);");
insertDrink(db,"latte","Espresso and Steamed Milk",R.drawable.latte);
insertDrink(db, "cappuccino", "This a Cappuccino", R.drawable.cap);
}
if (olderVersion < 2){
db.execSQL("delete from DRINK");
db.execSQL("alter table AUTO_INCREMENT =1"); //*** NEED HELP HERE***
insertDrink(db, "coff", "Espresso and Steamed Milk", R.drawable.latte);
}
}
I found this piece of code online but it's not working. Thank you.
db.execSQL("alter table AUTO_INCREMENT =1");
Deleteing the rows won't reset ROWID.
SQLite documentation states:
SQLite keeps track of the largest ROWID that a table has ever held
using the special SQLITE_SEQUENCE table. The SQLITE_SEQUENCE table is
created and initialized automatically whenever a normal table that
contains an AUTOINCREMENT column is created. The content of the
SQLITE_SEQUENCE table can be modified using ordinary UPDATE, INSERT,
and DELETE statements. But making modifications to this table will
likely perturb the AUTOINCREMENT key generation algorithm.
This sql should do what you need:
UPDATE SQLITE_SEQUENCE SET seq = <n> WHERE name = <table>
Where n is the sequence you wish to set and table is your table name
I copied an SQLite Database example, where I created a table with 3 fields/columns and inserted one record with 3 values, as follows:
>SQLiteDatabase db = openOrCreateDatabase("MyDB",MODE_PRIVATE,null);
>db.execSQL("CREATE TABLE IF NOT EXISTS FunnyNames(Email VARCHAR(255), FirstName VARCHAR(255), LastName VARCHAR(255));");
>db.execSQL("INSERT INTO FunnyNames VALUES('abath#aol.com','Anita','Bath')");
..and I received this error message
>12-28 11:35:00.896: E/SQLiteLog(8857): (1) table FunnyNames has 1 columns but 3 values were supplied
didn't I define the columns correctly?
IF NOT EXISTS only creates the table if it didn't exist. Likely you already have a table with that given name in the database file, and that table only has 1 column.
Uninstall your app or clear its data in the app manager to remove the old database file. Or add DROP TABLE IF EXISTS FunnyNames before the CREATE TABLE.
You've missed the primary key of the table. Every table needs an primary key (which is an unique id) for referencing data. Modify your create statement as follow:
CREATE TABLE IF NOT EXISTS FunnyNames(_id INTEGER PRIMARY KEY AUTOINCREMENT, Email VARCHAR(255), FirstName VARCHAR(255), LastName VARCHAR(255));
Hey i made a whole app without adding an autoincrement column but now i need this column to specify the max id so i created my database in my mainactivity like this.How can i modify this to add the autoincrement _id column ?
db = getActivity().openOrCreateDatabase("testDB2", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS test2(mac VARCHAR,mdp VARCHAR,obj VARCHAR);");
I don't want to create a seonc java classs only for the database because i did all the code like this.
You can't alter the sqlite table to add _id column as primary key after table created.
What you should do is creating a new table, then copy the old data to the new table.
See the faq from sqlite.org
db.execSQL("CREATE TABLE IF NOT EXISTS test2(autoincrement_id INTERGER PRIMARY KEY AUTOINCREMENT,mac VARCHAR,mdp VARCHAR,obj VARCHAR);");
only primary key can be autoincrement