Sqlite insert trigger on virtual table with condition - android

I am trying to insert on the virtual table only when the condition met to insert, like when the type is "-1" then only insert.
But it was inserting all the record
DROP TRIGGER if exists test_ai;
CREATE TRIGGER test_ai AFTER INSERT ON test
WHEN new.type = -1
BEGIN INSERT INTO
test_fts(body) VALUES (new.body);
END;
/*Create table */
CREATE TABLE `test` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `body` TEXT, `caption` TEXT, `type` INTEGER );
/*Create virtual table */
CREATE VIRTUAL TABLE test_fts USING fts5(body, content=test, content_rowid=id);
/* Insert into test table*/
insert into test(body, caption, type) values("5", "",-6);

It just looks like they're there, it's basically a virtual "copy" of the content table. However, only the rows inserted with the trigger will be returned in an FTS query. Try
SELECT * from test_fts where body MATCH '5'
It will not return the sample row. The trigger insert builds the FTS structure for the desired row(s).

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").

SQLite db update recreate table keep values

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;

How to set a default value to a TEXT column in Sqlite?

I have a simple table. I'm trying to put a default value to a TEXT column. Here is the table query:
"CREATE TABLE book(_id INTEGER PRIMARY KEY AUTOINCREMENT, book_id TEXT NOT NULL DEFAULT '0', book_name TEXT NOT NULL);"
It creates the table but the problem occurs when i try to insert a data. I was only trying with giving a book name to book_name, as i expected that the book_id would have a default value 0 to the column. But it doesn't and it adds the null value, so the row doesn't get inserted. I have also tried with this query:
"CREATE TABLE book(_id INTEGER PRIMARY KEY AUTOINCREMENT, book_id TEXT NOT NULL DEFAULT \'0\', book_name TEXT NOT NULL);"
But the problem remains the same. I have searched the stack overflow, and got some answers but they are old and not working for me right now. So has something changed on how to set the default value to a TEXT column in sqlite. Thanks in advance :)
EDIT
Here is the insert statement:
database.insert("book", null, cv);
Here cv is the object of ContentValues which contains only the value for the column book_name.
You can specify a default value for the column when you create the table. (It doesn't appear as though you can add a default using an ALTER statement, so you'll have to recreate your table.)
CREATE TABLE your_table_name
(MainContactName TEXT NOT NULL DEFAULT '')
For Example,
CREATE TABLE book(_id INTEGER PRIMARY KEY AUTOINCREMENT,book TEXT DEFAULT "abc");
now see that , default value is set to "abc"
Check sqllite documentation.
To alter table,
sqlitedbInstance.execSQL("alter table myTable add column Address TEXT DEFAULT 'ABC' ");

Android app, SQLite, FTS3, create virtual table if not exists

Beginner to SQLite/SQL. Building an Android app with FTS3 enabled, so I need to create virtual tables. I can't use this, because (according to my system log) virtual tables don't use IF NOT EXISTS syntax:
// Create the table if it doesn't exist.
db.transaction(function(tx){
tx.executeSql( 'CREATE TABLE IF NOT EXISTS User(UserId INTEGER NOT NULL PRIMARY KEY, FirstName TEXT NOT NULL, LastName TEXT NOT NULL)',[],nullHandler,errorHandler);
},errorHandler,successCallBack);
To confirm that my SQLite plug-in is working as expected, I have been using this instead:
// Create the table if it doesn't exist.
db.transaction(function(tx){
tx.executeSql( 'DROP TABLE User',[],nullHandler,errorHandler);
tx.executeSql( 'CREATE VIRTUAL TABLE User USING fts3 (UserId INTEGER NOT NULL PRIMARY KEY, FirstName TEXT NOT NULL, LastName TEXT NOT NULL)',[],nullHandler,errorHandler);
},errorHandler,successCallBack);
Which works mostly as expected (except that the UserId INTEGER NOT NULL PRIMARY KEY no longer works, returning null every time-- suggestions for a Virtual Table friendly way to add an incrementing integer also very welcome). But I don't want to drop the table every time, I want to keep it. How can I check for the existence of the table User and only create it if it doesn't exist?
According to the CREATE VIRTUAL TABLE documentation, the correct syntax is:
CREATE VIRTUAL TABLE IF NOT EXISTS User USING FTS4(...)
According to the FTS documentation, you cannot explicitly declare an autoincrementing column, but every table has an implicit column called docid or rowid.

How to use FTS3 in SQLite

I have table with almost 200k entries. When I tried search with LIKE, it was very slow. Now I decided to use FTS. So I created two indexes where search will be held. Then I created fts virtual table.
`CREATE TABLE [search_eng] (
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
[entry_id] INTEGER,
[re_value] TEXT,
[ke_value] TEXT,
[g_value] TEXT);
CREATE INDEX idx_se_re ON search_eng (re_value);
CREATE INDEX idx_se_gv ON search_eng (g_value);
CREATE VIRTUAL TABLE search_eng_fts USING fts3(id, entry_id, re_value, ke_value, g_value);`
I have no idea how to use new created FTS table. So my questions is how to use that virtual table to make search? Can you give an example?
This is explained in the documentation.
You do not need the two indexes for FTS searches.
You should declare the id column as INTEGER PRIMARY KEY.
You probably don't need the entry_id column in the FST table.
Copy the text into the FTS table:
INSERT INTO search_eng_fts(id, re_value, ke_value, g_value)
SELECT id, re_value, ke_value, g_value FROM search_eng;
Then you can use the MATCH operator to search in that table:
SELECT id FROM search_eng_fts WHERE re_value MATCH 'hello';

Categories

Resources