I appear to be having a problem with Virtual Tables in SQLite3.
Create Tables:
CREATE TABLE Test1 (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Value TEXT);
CREATE VIRTUAL TABLE Test2 USING fts4 (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Value TEXT);
As you can see they are essentially identical except one is Virtual for FTS4 support.
INSERT INTO Test1 (Value) values("test");
INSERT INTO Test2 (Value) values("test");
Results for Test1:
id Value
---------- ----------
1 test
Results for Test2:
id Value
---------- ----------
test
Is there a way to get SQLite3 to force the NOT NULL characteristic for Virtual Tables?
Thanks!
I believe you can use the rowid column, which is available in both standard and virtual SQLite tables, to achieve what you want.
CREATE VIRTUAL TABLE Test2 USING fts4 (Value TEXT);
When you want to insert a new record, just pass null as the value of the rowid:
INSERT INTO Test2(rowid, Value) VALUES(null, 'hello');
The default behavior in SQLite for assigning the rowid when the insert value is null is to increment the previous largest value by 1. This will behave similarly to what you had in mind when using AUTOINCREMENT.
To obtain the rowid in a query on your table, you can try something like this:
SELECT rowid, * FROM Test2;
Here is a link to the SQLite documentation which discusses the behavior of null with rowid. And here is a link which mentions that FTS tables do have a rowid column like regular tables.
Virtual tables are not implemented by SQLite itself but by some separate piece of code.
The FTS module does not support data types or constraints; its virtual tables have only plain text columns, and all columns (including your id column) are indexed for full-text searches.
As shown in the documentation, FTS tables have an implicit INTEGER PRIMARY KEY column which can be accessed as docid or rowid.
Related
This should be an easy one. I need the SQL to insert into a table that has only one column and it is and autoincrement field.
Similar to this post but SQLite (I am new to SQLite).
Inserting rows into a table with one IDENTITY column only
create table ConnectorIDs
(
ID integer primary key AUTOINCREMENT
);
--none of the following work
INSERT INTO ConnectorIDs VALUES(DEFAULT);
INSERT ConnectorIDs DEFAULT VALUES;
Yes this is strange and if you care here is the reason, if you want to tell me a better way. I have several different item tables that all can have many-to-many links between them but sparse. Instead of having n! bridge tables, or one bridge table with a "Type" that I can't guarantee truly maps to the correct table. I will have one ConnectorID table and each item with have a connectorID key. Then I can have one bridge table.
Insert a null value:
INSERT INTO ConnectorIDs VALUES(NULL);
From the docs:
If no ROWID is specified on the insert, or if the specified ROWID has a value of NULL, then an appropriate ROWID is created automatically.
So I'm making things complicated ...I think. A primary key basically is to make the row unique. Is that correct? Anyone want to show me an insert statement with the values for PK?
The SQLite documentation says:
On an INSERT, if the ROWID or INTEGER PRIMARY KEY column is not
explicitly given a value, then it will be filled automatically with an
unused integer, usually one more than the largest ROWID currently in
use. This is true regardless of whether or not the AUTOINCREMENT
keyword is used.
So, on a table like
CREATE TABLE test(id INTEGER PRIMARY KEY, descr TEXT);
an insert with a valid id could be
INSERT INTO test(descr) VALUES('this is a test');
A primary key, also called a primary keyword, is a key in a relational database that is unique for each record. It is a unique identifier, such as a driver license number, telephone number (including area code), or vehicle identification number (VIN). A relational database must always have one and only one primary key.
if you are using CREATE TABLE, if you are creating the primary key on a single field, you can use:
CREATE TABLE mytable (
field1 TEXT,
field2 INTEGER PRIMARY KEY,
field3 BLOB,
);
Reference more at: https://www.sqlite.org/lang_createtable.html & http://sqlite.org/faq.html#q11
In the SQLite documentation it says:
The parent key of a foreign key constraint is not allowed to use the
rowid. The parent key must used named columns only.
The parent key must be a named column or columns in the parent table,
not the rowid.
But does that apply to an alias of the rowid? For example in SQLite if you have a INTEGER PRIMARY KEY column then that column is essentially an alias of the rowid:
With one exception noted below, if a rowid table has a primary key
that consists of a single column and the declared type of that column
is "INTEGER" in any mixture of upper and lower case, then the column
becomes an alias for the rowid. Such a column is usually referred to
as an "integer primary key".
(Exception omitted; not relevant here)
There is a similar question here:
sql - Why does referencing a SQLite rowid cause foreign key mismatch? - Stack Overflow
If I take that example and modify it to use the alias (my integer primary key column) it appears to work:
sqlite> CREATE TABLE foo(a INTEGER PRIMARY KEY, name);
sqlite> create table bar(foo_rowid REFERENCES foo(a));
sqlite> INSERT INTO foo VALUES( NULL, "baz" );
sqlite> select * from foo;
a name
---------- ----------
1 baz
sqlite> INSERT INTO bar (foo_rowid) VALUES(1);
sqlite> select * from bar;
foo_rowid
----------
1
sqlite>
But is it legal to reference an alias of the rowid? Thanks.
If the internal rowid is not a named column, it might not keep the same values after a VACUUM, which would break the foreign key references.
If the rowid is named, it is guaranteed to keep its values.
Using an INTEGER PRIMARY KEY as the parent of a foreign key is allowed, and common.
I have table news (id, news_id, news_title) and I creat FTS table:
CREATE VIRTUAL TABLE news_search USING fts4 (news_title, tokenize=porter);
I use trigger to keep table NEWS and news_search in sync:
CREATE TRIGGER IF NOT EXISTS insert_news_trigger
AFTER INSERT ON news
BEGIN
INSERT OR IGNORE INTO news_search (news_title) VALUES (NEW.news_title);
END;
Question: how to use search? When I do MATCH in news_search table it returns me only records from this table, but I need *news_id* from news table. May be I should add *news_id* column to news_search table?
What is the proper way to use fts in sqlite?
Read the documentation; FTS tables also have a rowid column (also called docid) that you can set explicitly to the same value as the corresponding key of the original table.
Assuming that news.id is the rowid (i.e., INTEGER PRIMARY KEY), you should change your trigger to also copy that ID value into the news_search table.
You can the use that to look up the original record:
SELECT *
FROM news
WHERE id IN (SELECT docid
FROM news_search
WHERE news_title MATCH '😸')
I currently have a diagnosis table. I want to make the code and description fields searchable using FTS. As I understand it though, FTS tables don't support indexes and I need to be able to lookup Diagnosis by diagnosisID very quickly. Am I going to have to create a second virtual table with all of the data duplicated just for full text searching or am I missing a solution where I dont have to duplicate all of my diagnosis codes and descriptions?
CREATE TABLE Diagnosis (
diagnosisID INTEGER PRIMARY KEY NOT NULL,
code TEXT,
collect INTEGER NOT NULL,
description TEXT
);
Turns out an FTS table has a hidden rowid field, which you can populate when you are entering data:
sqlite> create virtual table test1 using fts3;
sqlite> insert into test1 values ("This is a document!");
sqlite> insert into test1(docid,content) values (5,"this is another document");
sqlite> select rowid,* from test1;
1|This is a document!
5|this is another document
You could create an integer field in your standard table that refers to the FTS table by rowid, and move the columns you wish to make text-searchable into the FTS table.
All the info you need here :)