cannot delete from view without exactly one key-preserved table - oracle11g

Currently, I want to delete this user's items from different cart tables. So I came up with it.
DELETE FROM (SELECT *
FROM EXH_CART EC, PRODUCT_CART PC, MEMBER M
WHERE PC.USER_NUM(+) = M.USER_NUM
AND EC.USER_NUM(+) = M.USER_NUM
AND M.USER_NUM = 6);
But this code gave me that error.
SQL error: ORA-01752: cannot delete from view without exactly one key-preserved table
01752. 00000 - "cannot delete from view without exactly one key-preserved table"
*Cause: The deleted table had
- no key-preserved tables;
- more than one key-preserved table, or
- the key-preserved table was an unmerged view.
*Action: Redefine the view or delete it from the underlying base tables.
table structure
How can I fix this error?? Please help.

Per the documentation of the DELETE command (https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_8005.htm#SQLRF01505), the syntax does not support multiple tables, joins, or other similar constructs. You must issue separate delete commands for each related table:
DELETE FROM MEMBER M WHERE M.USER_NUM = 6;
DELETE FROM EXH_CART EC WHERE EC.USER_NUM = 6;
DELETE FROM PRODUCT_CART PC WHERE PC.USER_NUM = 6;
COMMIT;
As I mentioned in the comments, ideally you would have a formal foreign key relationship between the child and parent tables, with the ON DELETE CASCADE option set so that you would then only have to delete the record from the parent table and let the database handle the child records automatically.

Related

Drop a table originally created with 'unknown tokenizer'?

I have a sqlite3 database. A single table inside this DB can't be dropped, the error message says unknown tokenizer: mm.
I tried it directly with the command DROP TABLE tablename; inside the newest SQLiteSpy v1.9.11 and also within .NET code and the official sqlite NuGet package v 1.0.103.
How can I drop a table where the tokenizer is unknown?
The documentation says:
For each FTS virtual table in a database, three to five real (non-virtual) tables are created to store the underlying data. These real tables are called "shadow tables". The real tables are named "%_content", "%_segdir", "%_segments", "%_stat", and "%_docsize", where "%" is replaced by the name of the FTS virtual table.
So to get rid of that table, drop the shadow tables:
DROP TABLE tablename_content;
DROP TABLE tablename_segdir;
DROP TABLE tablename_segments;
DROP TABLE tablename_stat;
DROP TABLE tablename_docsize;
And then use the (very dangerous) PRAGMA writable_schema to remove the remaining information about this table from the system table:
PRAGMA writable_schema = ON;
DELETE FROM sqlite_master WHERE type = 'table' AND name = 'tablename';
SQLite caches schema information, so then you need to close and re-open the database.

Replacing white spaces in the fields of a SQLite database [duplicate]

I would need to rename a few columns in some tables in a SQLite database.
I know that a similar question has been asked on stackoverflow previously, but it was for SQL in general, and the case of SQLite was not mentioned.
From the SQLite documentation for ALTER TABLE, I gather that it's not possible to do such a thing "easily" (i.e. a single ALTER TABLE statement).
I was wondering someone knew of a generic SQL way of doing such a thing with SQLite.
Note that as of version 3.25.0 released September 2018 you can now use ALTER TABLE to rename a column.
Example to rename Really Bad : Column Name to BetterColumnName
ALTER TABLE your_table
RENAME COLUMN [Really Bad : Column Name] TO BetterColumnName
Original "create new and drop old table" answer below.
Say you have a table and need to rename "colb" to "col_b":
First create the new table with a temporary name, based on the old table definition but with the updated column name:
CREATE TABLE tmp_table_name (
col_a INT
, col_b INT
);
Then copy the contents across from the original table.
INSERT INTO tmp_table_name(col_a, col_b)
SELECT col_a, colb
FROM orig_table_name;
Drop the old table.
DROP TABLE orig_table_name;
Last you rename the temporary table table to the original:
ALTER TABLE tmp_table_name RENAME TO orig_table_name;
Don't forget to re-create indexes, triggers, etc. The documentation gives a fuller picture of the gotchas and caveats.
Wrapping all this in a BEGIN TRANSACTION; and COMMIT; is also probably a good idea.
This was just fixed with 2018-09-15 (3.25.0)
Enhancements the ALTER TABLE command:
Add support for renaming columns within a table using ALTER TABLE table RENAME COLUMN oldname TO newname.
Fix table rename feature so that it also updates references to the renamed table in triggers and views.
You can find the new syntax documented under ALTER TABLE
The RENAME COLUMN TO syntax changes the column-name of table table-name into new-column-name. The column name is changed both within the table definition itself and also within all indexes, triggers, and views that reference the column. If the column name change would result in a semantic ambiguity in a trigger or view, then the RENAME COLUMN fails with an error and no changes are applied.
Image source: https://www.sqlite.org/images/syntax/alter-table-stmt.gif
Example:
CREATE TABLE tab AS SELECT 1 AS c;
SELECT * FROM tab;
ALTER TABLE tab RENAME COLUMN c to c_new;
SELECT * FROM tab;
db-fiddle.com demo
Android Support
As of writing, Android's API 27 is using SQLite package version 3.19.
Based on the current version that Android is using and that this update is coming in version 3.25.0 of SQLite, I would say you have bit of a wait (approximately API 33) before support for this is added to Android.
And, even then, if you need to support any versions older than the API 33, you will not be able to use this.
Digging around, I found this multiplatform (Linux | Mac | Windows) graphical tool called DB Browser for SQLite that actually allows one to rename columns in a very user friendly way!
Edit | Modify Table | Select Table | Edit Field. Click click! Voila!
However, if someone want to share a programmatic way of doing this, I'd be happy to know!
While it is true that there is no ALTER COLUMN, if you only want to rename the column, drop the NOT NULL constraint, or change the data type, you can use the following set of commands:
Note: These commands have the potential to corrupt your database, so make sure you have a backup
PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;
You will need to either close and reopen your connection or vacuum the database to reload the changes into the schema.
For example:
Y:\> sqlite3 booktest
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);
sqlite> insert into BOOKS VALUES ("NULLTEST",null);
Error: BOOKS.publication_date may not be NULL
sqlite> PRAGMA writable_schema = 1;
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
sqlite> PRAGMA writable_schema = 0;
sqlite> .q
Y:\> sqlite3 booktest
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> insert into BOOKS VALUES ("NULLTEST",null);
sqlite> .q
REFERENCES FOLLOW:
pragma writable_schema
When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file.
alter table
SQLite supports a limited subset of ALTER TABLE. The ALTER TABLE command in SQLite allows the user to rename a table or to add a new column to an existing table. It is not possible to rename a column, remove a column, or add or remove constraints from a table.
Recently I had to do that in SQLite3 with a table named points with the colunms id, lon, lat. Erroneusly, when the table was imported, the values for latitude where stored in the lon column and viceversa, so an obvious fix would be to rename those columns. So the trick was:
create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;
I hope this would be useful for you!
CASE 1 : SQLite 3.25.0+
Only the Version 3.25.0 of SQLite supports renaming columns. If your device is meeting this requirement, things are quite simple. The below query would solve your problem:
ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";
CASE 2 : SQLite Older Versions
You have to follow a different Approach to get the result which might be a little tricky
For example, if you have a table like this:
CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)
And if you wish to change the name of the column Location
Step 1: Rename the original table:
ALTER TABLE student RENAME TO student_temp;
Step 2: Now create a new table student with correct column name:
CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)
Step 3: Copy the data from the original table to the new table:
INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;
Note: The above command should be all one line.
Step 4: Drop the original table:
DROP TABLE student_temp;
With these four steps you can manually change any SQLite table.
Keep in mind that you will also need to recreate any indexes, viewers or triggers on the new table as well.
Quoting the sqlite documentation:
SQLite supports a limited subset of
ALTER TABLE. The ALTER TABLE command
in SQLite allows the user to rename a
table or to add a new column to an
existing table. It is not possible to rename a colum, remove a column, or add or remove constraints from a table.
What you can do of course is, create a new table with the new layout, SELECT * FROM old_table, and fill the new table with the values you'll receive.
First off, this is one of those things that slaps me in the face with surprise: renaming of a column requires creating an entirely new table and copying the data from the old table to the new table...
The GUI I've landed on to do SQLite operations is Base. It's got a nifty Log window that shows all the commands that have been executed. Doing a rename of a column via Base populates the log window with the necessary commands:
These can then be easily copied and pasted where you might need them. For me, that's into an ActiveAndroid migration file. A nice touch, as well, is that the copied data only includes the SQLite commands, not the timestamps, etc.
Hopefully, that saves some people time.
change table column < id > to < _id >
String LastId = "id";
database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
+"("
+ PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
+ PhraseContract.COLUMN_PHRASE + " text ,"
+ PhraseContract.COLUMN_ORDER + " text ,"
+ PhraseContract.COLUMN_FROM_A_LANG + " text"
+")"
);
database.execSQL("INSERT INTO " +
PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
" SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
" FROM " + PhraseContract.TABLE_NAME + "old");
database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");
Create a new column with the desired column name: COLNew.
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
Copy contents of old column COLOld to new column COLNew.
INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}
Note: brackets are necessary in above line.
As mentioned before, there is a tool SQLite Database Browser, which does this. Lyckily, this tool keeps a log of all operations performed by the user or the application. Doing this once and looking at the application log, you will see the code involved. Copy the query and paste as required. Worked for me. Hope this helps
From the official documentation
A simpler and faster procedure can optionally be used for some changes that do no affect the on-disk content in any way. The following simpler procedure is appropriate for removing CHECK or FOREIGN KEY or NOT NULL constraints, renaming columns, or adding or removing or changing default values on a column.
Start a transaction.
Run PRAGMA schema_version to determine the current schema version number. This number will be needed for step 6 below.
Activate schema editing using PRAGMA writable_schema=ON.
Run an UPDATE statement to change the definition of table X in the sqlite_master table: UPDATE sqlite_master SET sql=... WHERE type='table' AND name='X';
Caution: Making a change to the sqlite_master table like this will render the database corrupt and unreadable if the change contains a syntax error. It is suggested that careful testing of the UPDATE statement be done on a separate blank database prior to using it on a database containing important data.
If the change to table X also affects other tables or indexes or triggers are views within schema, then run UPDATE statements to modify those other tables indexes and views too. For example, if the name of a column changes, all FOREIGN KEY constraints, triggers, indexes, and views that refer to that column must be modified.
Caution: Once again, making changes to the sqlite_master table like this will render the database corrupt and unreadable if the change contains an error. Carefully test of this entire procedure on a separate test database prior to using it on a database containing important data and/or make backup copies of important databases prior to running this procedure.
Increment the schema version number using PRAGMA schema_version=X where X is one more than the old schema version number found in step 2 above.
Disable schema editing using PRAGMA writable_schema=OFF.
(Optional) Run PRAGMA integrity_check to verify that the schema changes did not damage the database.
Commit the transaction started on step 1 above.
One option, if you need it done in a pinch, and if your initial column was created with a default, is to create the new column you want, copy the contents over to it, and basically "abandon" the old column (it stays present, but you just don't use/update it, etc.)
ex:
alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically
This leaves behind a column (and if it was created with NOT NULL but without a default, then future inserts that ignore it might fail), but if it's just a throwaway table, the tradeoffs might be acceptable. Otherwise use one of the other answers mentioned here, or a different database that allows columns to be renamed.
need to rename a few columns in some tables
Another way is to use multiple SQLite3 commands to "rename" a column,
in "some" tables, repeat as needed:
.output tmp
SELECT "ALTER TABLE """|| sqlite_master.name ||""" RENAME COLUMN old_name TO new_name;" FROM sqlite_master
WHERE type = "table" AND sqlite_master.name NOT LIKE 'sqlite_%';
.read tmp
source
Since version 2018-09-15 (3.25.0)
sqlite supports renaming columns
https://sqlite.org/changes.html
sqlite3 yourdb .dump > /tmp/db.txt
edit /tmp/db.txt change column name in Create line
sqlite2 yourdb2 < /tmp/db.txt
mv/move yourdb2 yourdb

Sqlite: Are updates to two tables within an insert trigger atomic?

I refactored a table that stored both metadata and data into two tables, one for metadata and one for data. This allows metadata to be queried efficiently.
I also created an updatable view with the original table's columns, using sqlite's insert, update and delete triggers. This allows calling code that needs both data and metadata to remain unchanged.
The insert and update triggers write each incoming row as two rows - one in the metadata table and one in the data table, like this:
// View
CREATE VIEW IF NOT EXISTS Item as select n.Id, n.Title, n.Author, c.Content
FROM ItemMetadata n, ItemData c where n.id = c.Id
// Trigger
CREATE TRIGGER IF NOT EXISTS item_update
INSTEAD OF UPDATE OF id, Title, Author, Content ON Item
BEGIN
UPDATE ItemMetadata
SET Title=NEW.Title, Author=NEW.Author
WHERE Id=old.Id;
UPDATE ItemData SET Content=NEW.Content
WHERE Id=old.Id;
END;
Questions:
Are the updates to the ItemMetadata and ItemData tables atomic? Is there a chance that a reader can see the result of the first update before the second update has completed?
Originally I had the WHERE clauses be WHERE rowid=old.rowid but that seemed to cause random problems so I changed them to WHERE Id=old.Id. The original version was based on tutorial code I found. But after thinking about it I wonder how sqlite even comes up with an old rowid - after all, this is a view across multiple tables. What rowid does sqlite pass to an update trigger, and is the WHERE clause the way I first coded it problematic?
The documentation says:
No changes can be made to the database except within a transaction. Any command that changes the database (basically, any SQL command other than SELECT) will automatically start a transaction if one is not already in effect.
Commands in a trigger are considered part of the command that triggered the trigger.
So all commands in a trigger are part of a transaction, and atomic.
Views do not have a (usable) rowid.

INSERT OR REPLACE + foreign key ON DELETE CASCADE working too good

I am currently trying to create an sqlite database where I can import a table from another sqlite database (can't attach) and add some extra data to each column.
Since there is no INSERT OR UPDATE I came up with this:
I was thinking about splitting the data into two tables and join them afterwards so I can just dump the whole import into one table replacing everything that changed and manage the extra data separately since that does not change on import.
The first table (let's call it base_data) would look like
local_id | remote_id | base_data1 | base_data2 | ...
---------+-----------+------------+------------+----
besides the local_id everything would just be a mirror of the remote database (I'll probably add a sync timestamp but that does not matter now).
The second table would look similar but has remote_id set as foreign key
remote_id | extra_data1 | extra_data2 | ...
----------+-------------+-------------+----
CREATE TABLE extra_data (
remote_id INTEGER
REFERENCES base_data(remote_id)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED,
extra_data1 TEXT,
extra_data2 TEXT,
/* etc */
)
Now my idea was to simply INSERT OR REPLACE INTO base_data ... values because the database I import from has no sync timestamp or whatsoever and I would have to compare everything to find out what row I have to UPDATE / what to INSERT.
But here lies the problem: INSERT OR REPLACE is actually a DELETE followed by an INSERT and the delete part triggers the foreign key ON DELETE which I thought I could prevent by making the constraint DEFERRED. It does not work if I wrap INSERT OR REPLACE in a transaction either. It's always deleting my extra data although the same foreign key exists after the statement.
Is it possible to stop ON DELETE to trigger until the INSERT OR REPLACE is finished? Maybe some special transaction mode / pragma ?
It seems work if I replace the ON DELETE CASCADE part by a trigger like:
CREATE TRIGGER on_delete_trigger
AFTER DELETE ON base_data
BEGIN
DELETE FROM extra_data WHERE extra_data.remote_id=OLD.remote_id;
END;
That trigger is only triggered by a DELETE statement and should solve my problem so far.
(Answer provided by the OP in the question)
Additional info by jmathew, citing the documentation:
When the REPLACE conflict resolution strategy deletes rows in order to satisfy a constraint, delete triggers fire if and only if recursive triggers are enabled.
Assuming you only have a single foreign key relationship on a primary key in your referenced table (as you do in your example), this proved to be a fairly painless solution for me.
Simply disable foreign key checks, run the replace query, then enable foreign keys again.
If the replace query is the only query that runs while foreign keys are disabled, you can be assured that no foreign keys will be fouled up. If you are inserting a new row, nothing will have had a chance to be linked to it yet and if you are replacing a row, the existing row will not be removed or have its primary key changed by the query so the constraint will still hold once foreign keys are re-enabled.
SQLlite code looks something like this:
PRAGMA foreign_keys=OFF;
INSERT OR REPLACE ...;
PRAGMA foreign_keys=ON;
What about the reasons of such behavior, there's an explanation from PostgreSQL team:
Yeah, this is per SQL spec as far as we can tell. Constraint checks can
be deferred till end of transaction, but "referential actions" are not
deferrable. They always happen during the triggering statement. For
instance SQL99 describes the result of a cascade deletion as being that
the referencing row is "marked for deletion" immediately, and then
All rows that are marked for deletion are effectively deleted
at the end of the SQL-statement, prior to the checking of any
integrity constraints.

How do I rename a column in a SQLite database table?

I would need to rename a few columns in some tables in a SQLite database.
I know that a similar question has been asked on stackoverflow previously, but it was for SQL in general, and the case of SQLite was not mentioned.
From the SQLite documentation for ALTER TABLE, I gather that it's not possible to do such a thing "easily" (i.e. a single ALTER TABLE statement).
I was wondering someone knew of a generic SQL way of doing such a thing with SQLite.
Note that as of version 3.25.0 released September 2018 you can now use ALTER TABLE to rename a column.
Example to rename Really Bad : Column Name to BetterColumnName:
ALTER TABLE your_table
RENAME COLUMN "Really Bad : Column Name" TO BetterColumnName
According to keywords the use of "double-quotes" is the standard way
Original "create new and drop old table" answer below.
Say you have a table and need to rename "colb" to "col_b":
First create the new table with a temporary name, based on the old table definition but with the updated column name:
CREATE TABLE tmp_table_name (
col_a INT
, col_b INT
);
Then copy the contents across from the original table.
INSERT INTO tmp_table_name(col_a, col_b)
SELECT col_a, colb
FROM orig_table_name;
Drop the old table.
DROP TABLE orig_table_name;
Last you rename the temporary table table to the original:
ALTER TABLE tmp_table_name RENAME TO orig_table_name;
Don't forget to re-create indexes, triggers, etc. The documentation gives a fuller picture of the gotchas and caveats.
Wrapping all this in a BEGIN TRANSACTION; and COMMIT; is also probably a good idea.
This was just fixed with 2018-09-15 (3.25.0)
Enhancements the ALTER TABLE command:
Add support for renaming columns within a table using ALTER TABLE table RENAME COLUMN oldname TO newname.
Fix table rename feature so that it also updates references to the renamed table in triggers and views.
You can find the new syntax documented under ALTER TABLE
The RENAME COLUMN TO syntax changes the column-name of table table-name into new-column-name. The column name is changed both within the table definition itself and also within all indexes, triggers, and views that reference the column. If the column name change would result in a semantic ambiguity in a trigger or view, then the RENAME COLUMN fails with an error and no changes are applied.
Image source: https://www.sqlite.org/images/syntax/alter-table-stmt.gif
Example:
CREATE TABLE tab AS SELECT 1 AS c;
SELECT * FROM tab;
ALTER TABLE tab RENAME COLUMN c to c_new;
SELECT * FROM tab;
db-fiddle.com demo
Android Support
As of writing, Android's API 27 is using SQLite package version 3.19.
Based on the current version that Android is using and that this update is coming in version 3.25.0 of SQLite, I would say you have bit of a wait (approximately API 33) before support for this is added to Android.
And, even then, if you need to support any versions older than the API 33, you will not be able to use this.
Digging around, I found this multiplatform (Linux | Mac | Windows) graphical tool called DB Browser for SQLite that actually allows one to rename columns in a very user friendly way!
Edit | Modify Table | Select Table | Edit Field. Click click! Voila!
However, if someone want to share a programmatic way of doing this, I'd be happy to know!
While it is true that there is no ALTER COLUMN, if you only want to rename the column, drop the NOT NULL constraint, or change the data type, you can use the following set of commands:
Note: These commands have the potential to corrupt your database, so make sure you have a backup
PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;
You will need to either close and reopen your connection or vacuum the database to reload the changes into the schema.
For example:
Y:\> sqlite3 booktest
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);
sqlite> insert into BOOKS VALUES ("NULLTEST",null);
Error: BOOKS.publication_date may not be NULL
sqlite> PRAGMA writable_schema = 1;
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
sqlite> PRAGMA writable_schema = 0;
sqlite> .q
Y:\> sqlite3 booktest
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> insert into BOOKS VALUES ("NULLTEST",null);
sqlite> .q
REFERENCES FOLLOW:
pragma writable_schema
When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file.
alter table
SQLite supports a limited subset of ALTER TABLE. The ALTER TABLE command in SQLite allows the user to rename a table or to add a new column to an existing table. It is not possible to rename a column, remove a column, or add or remove constraints from a table.
Recently I had to do that in SQLite3 with a table named points with the colunms id, lon, lat. Erroneusly, when the table was imported, the values for latitude where stored in the lon column and viceversa, so an obvious fix would be to rename those columns. So the trick was:
create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;
I hope this would be useful for you!
CASE 1 : SQLite 3.25.0+
Only the Version 3.25.0 of SQLite supports renaming columns. If your device is meeting this requirement, things are quite simple. The below query would solve your problem:
ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";
CASE 2 : SQLite Older Versions
You have to follow a different Approach to get the result which might be a little tricky
For example, if you have a table like this:
CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)
And if you wish to change the name of the column Location
Step 1: Rename the original table:
ALTER TABLE student RENAME TO student_temp;
Step 2: Now create a new table student with correct column name:
CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)
Step 3: Copy the data from the original table to the new table:
INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;
Note: The above command should be all one line.
Step 4: Drop the original table:
DROP TABLE student_temp;
With these four steps you can manually change any SQLite table.
Keep in mind that you will also need to recreate any indexes, viewers or triggers on the new table as well.
Quoting the sqlite documentation:
SQLite supports a limited subset of
ALTER TABLE. The ALTER TABLE command
in SQLite allows the user to rename a
table or to add a new column to an
existing table. It is not possible to rename a colum, remove a column, or add or remove constraints from a table.
What you can do of course is, create a new table with the new layout, SELECT * FROM old_table, and fill the new table with the values you'll receive.
First off, this is one of those things that slaps me in the face with surprise: renaming of a column requires creating an entirely new table and copying the data from the old table to the new table...
The GUI I've landed on to do SQLite operations is Base. It's got a nifty Log window that shows all the commands that have been executed. Doing a rename of a column via Base populates the log window with the necessary commands:
These can then be easily copied and pasted where you might need them. For me, that's into an ActiveAndroid migration file. A nice touch, as well, is that the copied data only includes the SQLite commands, not the timestamps, etc.
Hopefully, that saves some people time.
change table column < id > to < _id >
String LastId = "id";
database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
+"("
+ PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
+ PhraseContract.COLUMN_PHRASE + " text ,"
+ PhraseContract.COLUMN_ORDER + " text ,"
+ PhraseContract.COLUMN_FROM_A_LANG + " text"
+")"
);
database.execSQL("INSERT INTO " +
PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
" SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
" FROM " + PhraseContract.TABLE_NAME + "old");
database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");
Create a new column with the desired column name: COLNew.
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
Copy contents of old column COLOld to new column COLNew.
INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}
Note: brackets are necessary in above line.
As mentioned before, there is a tool SQLite Database Browser, which does this. Lyckily, this tool keeps a log of all operations performed by the user or the application. Doing this once and looking at the application log, you will see the code involved. Copy the query and paste as required. Worked for me. Hope this helps
From the official documentation
A simpler and faster procedure can optionally be used for some changes that do no affect the on-disk content in any way. The following simpler procedure is appropriate for removing CHECK or FOREIGN KEY or NOT NULL constraints, renaming columns, or adding or removing or changing default values on a column.
Start a transaction.
Run PRAGMA schema_version to determine the current schema version number. This number will be needed for step 6 below.
Activate schema editing using PRAGMA writable_schema=ON.
Run an UPDATE statement to change the definition of table X in the sqlite_master table: UPDATE sqlite_master SET sql=... WHERE type='table' AND name='X';
Caution: Making a change to the sqlite_master table like this will render the database corrupt and unreadable if the change contains a syntax error. It is suggested that careful testing of the UPDATE statement be done on a separate blank database prior to using it on a database containing important data.
If the change to table X also affects other tables or indexes or triggers are views within schema, then run UPDATE statements to modify those other tables indexes and views too. For example, if the name of a column changes, all FOREIGN KEY constraints, triggers, indexes, and views that refer to that column must be modified.
Caution: Once again, making changes to the sqlite_master table like this will render the database corrupt and unreadable if the change contains an error. Carefully test of this entire procedure on a separate test database prior to using it on a database containing important data and/or make backup copies of important databases prior to running this procedure.
Increment the schema version number using PRAGMA schema_version=X where X is one more than the old schema version number found in step 2 above.
Disable schema editing using PRAGMA writable_schema=OFF.
(Optional) Run PRAGMA integrity_check to verify that the schema changes did not damage the database.
Commit the transaction started on step 1 above.
One option, if you need it done in a pinch, and if your initial column was created with a default, is to create the new column you want, copy the contents over to it, and basically "abandon" the old column (it stays present, but you just don't use/update it, etc.)
ex:
alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically
This leaves behind a column (and if it was created with NOT NULL but without a default, then future inserts that ignore it might fail), but if it's just a throwaway table, the tradeoffs might be acceptable. Otherwise use one of the other answers mentioned here, or a different database that allows columns to be renamed.
need to rename a few columns in some tables
Another way is to use multiple SQLite3 commands to "rename" a column,
in "some" tables, repeat as needed:
.output tmp
SELECT "ALTER TABLE """|| sqlite_master.name ||""" RENAME COLUMN old_name TO new_name;" FROM sqlite_master
WHERE type = "table" AND sqlite_master.name NOT LIKE 'sqlite_%';
.read tmp
source
Since version 2018-09-15 (3.25.0)
sqlite supports renaming columns
https://sqlite.org/changes.html
sqlite3 yourdb .dump > /tmp/db.txt
edit /tmp/db.txt change column name in Create line
sqlite2 yourdb2 < /tmp/db.txt
mv/move yourdb2 yourdb

Resources