Indexing SQLite database: Empty Index ? - sqlite

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.

Related

Can I change the type of an index on the fly without re-creating the table?

I have always used a custom implementation of SQLite, and it had the "LATIN_NOCASE" collation.
I am now using System.Data.SQLite, and it doesn't have this collation, as I have found out now.
I would therefore like to change all indexes from LATIN_NOCASE to NOCASE.
Can I somehow do that with one line of code, or do I have to recreate the table / the indexes?
SQLite is designed as a lightweight, embedded database where large changes to the database are not supposed to happen at runtime, so it has no ALTER INDEX command: http://www.sqlite.org/lang.html.

copy sqlite index from one database to another

I have a massive database (~800 GB) with several indexed tables. I need to copy one table (including indexes) to a new database. Copying the table itself is pretty straightforward.
$ sqlite3 newDB
> attach database 'oldDB.db' as oldDB
> create table newTable as select * from oldDB.oldTable
But I can't seem to find any information on a way to also copy over an index. Is there any way to do this? Since the tables are so large I'd really like to avoid having to re-index them.
SQLite has no mechanism to copy index contents.
If this particular table would be the majority of the data in the database, the fastest way to copy it would be to copy the database file and then to drop all other tables.
But otherwise, there you cannot avoid the reindex operation.
Please note that CREATE TABLE ... AS ... does copy only the contents of the table, but not the complete table definition (such as column types or constraints).
Copying large table in a single transaction is not a good idea. If you really have to you should turn off journaling first (destination database):
PRAGMA journal_mode=OFF;
As the others have stated, the index cannot be broken out. I suspect that time spent copying the database and then dropping a very large table would be longer than just -> 1. creating the new destination database, 2. determining the original CREATE TABLE statement (from the SQLITE_MASTER table of the source database) and recreating the table in the destination database. Then 3. just ATTACH your destination database to the source database and INSERT INTO destinationdb.tablename SELECT * FROM sourcedb.tablename;* to get the copy rolling.

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.

Dropping a SQLite database index and then adding it back on

I am inserting a large number of records into a SQLite database on Android. To improve insert times, I am considering creating the index on the table after data has been fully added.
My question is, at what point does the database actually build the index against values on the table? Does it happen as soon as I issue the SQL statement (create index index_name on table ...), or can the database defer it until the first query arrives?
Thanks,
Ranjit
It creates the index immediately you issue the create index command. The relevant code is in sqlite3CreateIndex and this will create the index and write it to disk (except for the special case where it's called as part of a database open operation but that's not the case when a user creates an index).

SQLite Modify Column

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.

Resources