SQLite FTS example doesn't work - sqlite

I've downloaded the latest SQLite 3.7.15.2 shell (Win32) and tried to execute one of the FTS examples exactly as it is written at http://sqlite.org/fts3.html#section_3
-- Virtual table declaration
CREATE VIRTUAL TABLE docs USING fts3();
-- Virtual table data
INSERT INTO docs(docid, content) VALUES(1, 'a database is a software system');
INSERT INTO docs(docid, content) VALUES(2, 'sqlite is a software system');
INSERT INTO docs(docid, content) VALUES(3, 'sqlite is a database');
-- Return the set of documents that contain the term "sqlite", and the
-- term "database". This query will return the document with docid 3 only.
SELECT * FROM docs WHERE docs MATCH 'sqlite AND database';
but in spite of last comment SELECT resulted in empty set. Is it a bug in SQLite or just outdated documentation? (and what is the correct syntax for that?).
What is most important for me is that query
SELECT * FROM docs WHERE docs MATCH '(database OR sqlite) NEAR/5 system';
doesn't work either and that type of queries I need in my app. Is there any other way to write it so it would work?

The example from the documentation uses the enhanced query syntax.
Check that PRAGMA compile_options; includes ENABLE_FTS3_PARENTHESIS.
That your NEAR query does not work is not a problem with compilation options:
> SELECT * FROM docs WHERE docs MATCH '(database OR sqlite) NEAR/5 system';
Error: malformed MATCH expression: [(database OR sqlite) NEAR/5 system]
The problem is that, according to the documentation, NEAR does work only with basic search expressions:
A NEAR query is specified by putting the keyword "NEAR" between two phrase, term or prefix queries.
So you have to rewrite your search expression accordingly:
> SELECT * FROM docs WHERE docs MATCH '(database NEAR/5 system) OR (sqlite NEAR/5 system)';
a database is a software system
sqlite is a software system

I don't know if it is the docs or if it is a bug with SQLite, but here are some alternatives:
For AND queries
Doesn't work:
select * from docs where docs match 'sqlite AND database';
Works (using implied AND):
select * from docs where docs match 'sqlite database';
OR seems to work:
select * from docs where docs match 'sqlite OR database';
For OR + NEAR queries:
Doesn't Work:
SELECT * FROM docs WHERE docs MATCH '(database OR sqlite) NEAR/5 system';
Works:
SELECT * FROM docs WHERE docs MATCH 'database NEAR/5 system'
UNION
SELECT * FROM docs WHERE docs MATCH 'sqlite NEAR/5 system'
EDIT: For the form mentioned in the comments (word11 OR word12 OR word13) NEAR/2 (word21 OR word22 OR word23) NEAR/2 (word31 OR word32 OR word33. This is the best I could do is to put all combinations together with a UNION:
SELECT * FROM docs WHERE docs MATCH 'word11 NEAR/2 word21 NEAR/2 word31'
UNION
SELECT * FROM docs WHERE docs MATCH 'word11 NEAR/2 word22 NEAR/2 word32'
UNION
SELECT * FROM docs WHERE docs MATCH 'word11 NEAR/2 word23 NEAR/2 word33'
UNION
SELECT * FROM docs WHERE docs MATCH 'word12 NEAR/2 word21 NEAR/2 word31'
...
The above of course creates large amounts of SQL. If your words are similar in that only the endings differ, you could use wildcards:
SELECT * FROM docs WHERE docs MATCH 'word1* NEAR/2 word2* NEAR/2 word3*';

According to the documentation (https://www.sqlite.org/fts3.html), parentheses are not supported by default.
Look at part 2. Compiling and Enabling FTS3 and FTS4.

Related

SQLIte : Query to find all keywords in sqlite

I am working with SQLite. I need to know a query that retrieves all KEYWORDS in SQLite. Ex:
For Oracle: select * from v$reserved_words
For MySQL: select * from mysql.help_keyword
Above query will show all keywords in the corresponding database. Like this, I need a query for SQLite. Anyone knows please let me know.
There is no way to dynamically retrieve the list of reserved words, with a system table or a pragma.
The documentation lists the (currently) 124 keywords. It seems that the actual list also depends on the compile-time options.

Sqlite FTS4 Get rows with Order of terms in query

My virtual table is:
CREATE VIRTUAL TABLE docs USING fts4();
INSERT INTO docs(docid, content) VALUES(1, 'sqlite is a database');
INSERT INTO docs(docid, content) VALUES(2, 'my database is sqlite');
When I use this query:
SELECT * FROM docs WHERE docs MATCH 'sqlite AND database';
it returns both 2 records in the table because both of them contain the term "sqlite" and the term "database".
Now, I want to search for records that contain the term "sqlite" and the term "database" with this rule:
The order in which the terms appear in the document has to be the same as the order in which they appear in the query (document with docid 1 only).
Is it possible?
FTS queries cannot restrict the order of terms, except for phrase searches, which require consecutive terms (e.g., "sqlite database" would not match sqlite is a database).
You have to restrict the results afterwards:
SELECT ... WHERE docs MATCH 'sqlite AND database'
AND content LIKE '%sqlite%database%';

How can you exclude a search term in an SQLite fulltext search?

I am using DB Browser for SQLite. The documentation for SQLite's fts3 says "FTS is primarily designed to support Boolean full-text queries". I built a virtual table using fts4 and successfully executed a few WHERE ... MATCH queries. But the following attempts give errors:
SELECT id FROM histsearch WHERE id MATCH ("-1456" IN BOOLEAN MODE);
SELECT id FROM histsearch WHERE NOT EXIST id MATCH ("1457");
Is the problem in DB Browser or in SQLite? How else can I write this query so it will work?
SQLite's full text service (fts3) basically offers Boolean Mode by default, no search modifier needed. DB Browser uses fts's standard query syntax, so NOT is not supported. To exclude a term, do something like
SELECT * FROM indexed WHERE indexed MATCH 'sqlite -database';
Edit: however, you cannot only exclude search terms in fulltext search:
An FTS query may not consist entirely of terms or term-prefix queries with unary "-" operators attached to them.
You'll have to use NOT LIKE for that.

Sqlite FTS, Using OR between match operators

When I execute the following query in a sqlite engine (android or sqlitebrowser) it throws an exception that says unable to use function MATCH in the requested context.
select
a.Body1,
b.Body2
from
tbl1_fts as a,
tbl2_fts as b
where
a.ID = b.ParentID and
(
a.Body1 match('value') or
b.Body2 match('value')
)
-Both tables have fts.
-Using And operator between two matches (instead of OR) runs normally.
How can I fix this or change the query to find rows with above condition?
you can not use OR Operation, just change your Match Keyword.
like
SELECT * FROM docs WHERE docs MATCH 'sqlite OR database';
OR maybe you can use union
SELECT docid FROM docs WHERE docs MATCH 'sqlite AND database'
UNION
SELECT docid FROM docs WHERE docs MATCH 'library';
MATCH as a function would have two parameters:
... WHERE match('value', SomeColumn) ...
However, the usual method of using MATCH is as an operator:
... WHERE SomeColumn MATCH 'value' ...
MATCH has to be used without parentheses.
The AND and OR operators must be in capital letters when used with FTS.

A limitation of Sqlite3's full text search doesn't allow ORs with MATCHes. Workaround?

Sqlite3's full text search facility - FTS3 - allows to use MATCH operator for fast full-text search:
SELECT ItemId FROM docs WHERE docs.text MATCH 'linux'
However, it does not support OR operator anywhere in an SQL query where there's a MATCH (source: 1, 2):
SELECT ItemId FROM docs WHERE docs.text MATCH 'linux' OR column=value
error: unable to use function MATCH in the requested context
(Not to be confused with OR operator in the FTS3 query itself, i.e. SELECT ItemId FROM docs WHERE docs.text MATCH 'linux OR unix'. This works fine.)
Is there a way to rewrite the query so that it works (even if it's somewhat slower)?
Rewriting the query using temporary views will work as expected:
CREATE TEMP VIEW view1 AS SELECT ItemId FROM docs WHERE docs.text MATCH 'linux'
SELECT * FROM docs WHERE ItemId IN view1 OR column=value
DROP VIEW view1
The speed will be comparable to that of a "direct" query (without the temporary view) if the temporary view is not "sweeping", i.e. it does not generate a lot of rows.

Resources