SQLite Modify Column - sqlite

I need to modify a column in a SQLite database but I have to do it programatically due to the database already being in production. From my research I have found that in order to do this I must do the following.
Create a new table with new schema
Copy data from old table to new table
Drop old table
Rename new table to old tables name
That seems like a ridiculous amount of work for something that should be relatively easy. Is there not an easier way? All I need to do is change a constraint on a existing column and give it a default value.

That's one of the better-known drawbacks of SQLite (no MODIFY COLUMN support on ALTER TABLE), but it's on the list of SQL features that SQLite does not implement.
edit: Removed bit that mentioned it may being supported in a future release as the page was updated to indicate that is no longer the case

If the modification is not too big (e.g. change the length of a varchar), you can dump the db, manually edit the database definition and import it back again:
echo '.dump' | sqlite3 test.db > test.dump
then open the file with a text editor, search for the definition you want to modify and then:
cat test.dump | sqlite3 new-test.db

As said here, these kind of features are not implemented by SQLite.
As a side note, you could make your two first steps with a create table with select:
CREATE TABLE tmp_table AS SELECT id, name FROM src_table

When I ran "CREATE TABLE tmp_table AS SELECT id, name FROM src_table", I lost all the column type formatting (e.g., time field turned into a integer field
As initially stated seems like it should be easier, but here is what I did to fix. I had this problem b/c I wanted to change the Not Null field in a column and Sqlite doesnt really help there.
Using the 'SQLite Manager' Firefox addon browser (use what you like). I created the new table by copying the old create statement, made my modification, and executed it. Then to get the data copied over, I just highlighted the rows, R-click 'Copy Row(s) as SQL', replaced "someTable" with my table name, and executed the SQL.

Various good answers already given to this question, but I also suggest taking a look at the sqlite.org page on ALTER TABLE which covers this issue in some detail: What (few) changes are possible to columns (RENAME|ADD|DROP) but also detailed workarounds for other operations in the section Making Other Kinds Of Table Schema Changes and background info in Why ALTER TABLE is such a problem for SQLite. In particular the workarounds point out some pitfalls when working with more complex tables and explain how to make changes safely.

Related

How to Handle BQ GA Export Changes?

I'm trying to reprocess ga_sessions_yyyymmdd data but am finding the ga_sessions never used to have a field called [channelGrouping] but it does in more recent data.
So my jobs work fine for the latest version of ga_sessions but when i try reprocess earleir ga_sessions data the job fails as it's missing the [channelGrouping] field.
Obviously usually this is what you want, but in this case it's not. I want to make sure i'm sticking to the latest ga_sessions schema and would like the job to just set missing cols to null for when they did not exist.
Is there any way around this?
Perhaps i need to make an empty table called ga_sessions_template_latest and union it on to whatever ga_sessions_ daily table i'm handling - maybe this will 'upgrade' the old ga_sessions to the new structure.
Attached is a screenshot of exactly what i mean (my union idea will actually be horrible due to nested fields in ga_sessions).
I don't have such a script yet. But since the tables are under your project you are able to update them. You can write a script and update the schema on all tables with missing columns from the most recent schema set.
I envision a script that gets most recent table schema.
Then goes back one by one to past tables, does a compare, identifies the missing columns, defines them as not required and nullable, and reads the schema + applies the additional columns and runs the update on the table. Data won't be modified, you will have just additional columns with null values.
you can try out for some also from the Web UI.

how to alter table multiple column in sqlite3

ALTER TABLE a add (OWNER_NAME VARCHAR2,OWNER_PARENT VARCHAR2);
Is it possible to alter table add MULTIPLE columns in a single statement in sqlite3?
The SQLite documentation provides the following picture to illustrate how the ALTER TABLE is understood by SQLite.
So, it does not seem possible to add multiple columns in a single ALTER TABLE command.
Reference: SQLite Query Language: ALTER TABLE
EDIT:
SQLite is a bit rigid when it comes to modifying existing tables and has limited support for the ALTER TABLE query.
Some more information can be found following this link: How do I add or delete columns from an existing table in SQLite.
The link also provides a workaround to carry out complex table modifications.
In a nutshell (emphasis mine):
If you want to make more complex changes in the structure of a table, you will have to recreate the table. You can save existing data to a temporary table, drop the old table, create the new table, then copy the data back in from the temporary table.

External Content FTS4 Tables in an attached database

I need to add FTS to an existing database.
Started to test external content FTS tables, where the FTS indexes reside in the default (main) DB. Everything worked satisfactorily, except a few things (such as index rebuild) could take considerable amount of time.
Then I read about the possibility to put FTS index into attached DB. This seemed to promise several advantages, hence I decided to give it a try. However, all my trials failed. Here are a few examples:
Situation
We have a table 'account' with a text column 'code', and
Want to create FTS index for that column and place it into separate database file
Test1) ERROR: near ".": syntax error
ATTACH 'ZipFts.sdf' AS ZipFts; CREATE VIRTUAL TABLE ZipFts.account USING fts4(content=account, code);
INSERT INTO ZipFts.account(ZipFts.account) VALUES('rebuild');
Test 2) ERROR: Stack overflow (infinite recursion inside sqlite engine)
ATTACH 'ZipFts.sdf' AS ZipFts; CREATE VIRTUAL TABLE ZipFts.account USING fts4(content=account, code);
INSERT INTO ZipFts.account(account) VALUES('rebuild');
Test3) ERROR: no such table: ZipFts.account
ATTACH 'ZipFts.sdf' AS ZipFts; CREATE VIRTUAL TABLE ZipFts.ZipFts_account USING fts4(content="account", code);
INSERT INTO ZipFts_account(ZipFts_account) VALUES('rebuild');
Test4) ERROR: no such table: ZipFts.main.account
ATTACH 'ZipFts.sdf' AS ZipFts; CREATE VIRTUAL TABLE ZipFts.ZipFts_account USING fts4(content="main.account", code);
INSERT INTO ZipFts_account(ZipFts_account) VALUES('rebuild');
Does anybody know how these things work? Thanks in advance.
After some searching in sqlite3.c I found what might be the answer.
Look at the bottom of the function fts3ReadExprList(). The name of the content table is prefixed with the DB name here! This explains everything.
Moreover, this seems to be the only non-trivial use of zContentTbl (= the name of the content table). When I slightly modified fts3ReadExprList() function as shown in the code underneath, the problem disappeared.
// Code inserted by #JS-->
// Do not prefix zContentTbl with the database name. The table might reside in main database, for example.
if( p->zContentTbl){
fts3Appendf(pRc, &zRet, " FROM '%q' AS x", p->zContentTbl);
}
else
// <--#JS
fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
...
Note that I did not test the code sufficiently. (So far I only know that the FTS index was created.)
Anyway, for the time being, I consider this an SQLite bug and I'll try to go on with my fix.
I think this is as designed.
If it were otherwise, the underlying table for an external content table could change as databases are attached or detached.
You might be able to achieve this using a contentless FTS Table though.
Dan Kennedy.

Indexing SQLite database: Empty Index ?

I have a .sqlite db which contains only one table. That table contains three columns and I am interested in indexing one column ONLY.
The problem is, when I perform the indexing, I got an empty index table !
I am using SQLite Manager add-ons for Firefox. This is the syntax that appears before I confirm the indexing:
CREATE INDEX "main"."tableIndex" ON "table" ("column1" ASC)
I don't know what is the problem here. I tried this tool - long time ago - with another database and it works fine.
Any suggestion ?
You cannot "see" the contents of a database index. No table or table-like structure is created that corresponds to the index. So there is nothing to look at that could be empty.
If the CREATE INDEX command ran without error, you can be confident that the index was created and will continue to be maintained by SQLite as you add, remove, and update data.
As per the comments, below, #iturki is actually trying to index for full text search. SQLite supports several extensions for full text search but they are not implemented through the stanard CREATE INDEX command. See this reference.
Try use VACUUM query. It will completely rebuild sqlite database file and will rebuild all indices and reset all ROWID etc.

Sqlite: Create a table and fill with information only once

I have an appcelerator titanium project (you don't need to be familiar with the platform to help me) that I am using to create an iOS app. I want to have a database with a table that is filled with several rows for the first time, and then left alone after the first time.
I know you can create a table if it doesn't exist. Is there something similar for Inserting data?
Thanks!
Expanding on MPelletier's response with some Titanium-specific code, you could do the following in your project:
var my_db = Ti.Database.open('nameofdb');
var my_result_set = my_db.execute('SELECT * FROM MyTable');
var records = my_result_set.rowCount;
The records variable will indicate whether or not you have data in your table and then you can act accordingly.
There are a couple of nice ORM-ish utilities out there for Titanium: TiStore and Joli are the two I've used. Both are inspired by ActiveRecord and can be helpful in reducing your DB-related code. They're on Github if you want to know more about them!
There's INSERT OR REPLACE if you want, but you might as well just check against the number of rows on the table:
SELECT COUNT(*) FROM MyTable;
Then decide to enter them on that.
You can create your DB and insert data in it via SQLLiteManager or whatever tool you want and then dump it.
Take the file you dumped, put it in your Titanium project folder (somewhere in the Resources folder).
Then this line of code will take the content of the .sqlite file and insert it in the iOS db:
var db = Ti.Database.install('../your-db.sqlite', 'your-db-name');
Just don't forget the CREATE IF NOT EXISTS statement in your SQL file.
Or use REPLACE instead of INSERT as MPelletier said.

Resources