Sqlite fts4 case sensitive - sqlite

Very new to Sqlite3 and I finally have an FTS4 search working, but am stumped how to code for Case-Sensitive. I have a Database with tblMain that has two BLOB_TEXT columns, advOne and advTwo
CREATE VIRTUAL TABLE tFind USING FTS4(aOne, aTwo);
// populate tFind here
SELECT FROM tFind WHERE aOne MATCH 'Fine';
This works fast and returns records with
feeling fine and
a Fine was levied
I need to find the records with only the case sensitive Fine in them.
How do I word the line?
I am using Lazarus and Ubuntu if that makes any difference.

The default tokenizer ignores case.
You'd have to install your own custom tokenizer.

Related

Updating an SQLite database via an ODBC linked table in Access

I am having an issue with an SQLite database. I am using the SQLite ODBC from http://www.ch-werner.de/sqliteodbc/ Installed the 64-bit version and created the ODBC with these settings:
I open my Access database and link to the datasource. I can open the table, add records, but cannot delete or edit any records. Is there something I need to fix on the ODBC side to allow this? The error I get when I try to delete a record is:
The Microsoft Access database engine stopped the process because you and another user are attempting to change the same data at the same time.
When I edit a record I get:
The record has been changed by another user since you started editing it. If you save the record, you will overwrite the changed the other user made.
Save record is disabled. Only copy to clipboard or drop changes is available.
My initial attempt to recreate your issue was unsuccessful. I used the following on my 32-bit test VM:
Access 2010
SQLite 3.8.2
SQLite ODBC Driver 0.996
I created and populated the test table [tbl1] as documented here. I created an Access linked table and when prompted I chose both columns ([one] and [two]) as the Primary Key. When I opened the linked table in Datasheet View I was able to add, edit, and delete records without incident.
The only difference I can see between my setup and yours (apart from the fact that I am on 32-bit and you are on 64-bit) is that in the ODBC DSN settings I left the Sync.Mode setting at its default value of NORMAL, whereas yours appears to be set to OFF.
Try setting your Sync.Mode to NORMAL and see if that makes a difference.
Edit re: comments
The solution in this case was the following:
One possible workaround would be to create a new SQLite table with all the same columns plus a new INTEGER PRIMARY KEY column which Access will "see" as AutoNumber. You can create a unique index on (what are currently) the first four columns to ensure that they remain unique, but the new new "identity" (ROWID) column is what Access would use to identify rows for CRUD operations.
I had this problem too. I have a table with a primary key on a VARCHAR(30) (TEXT) field.
Adding an INTEGER PRIMARY KEY column didn't help at all. After lots of testing I found the issue was with a DATETIME field I had in the table. I removed the DATETIME field and I was able to update record values in MS-Access datasheet view.
So now any DATETIME fields I need in SQLite, I declare as VARCHAR(19) so they some into Access via ODBC as text. Not perfect but it works. (And of course SQLite doesn't have a real DATETIME field type anyway so TEXT is just fine and will convert OK)
I confirmed it's a number conversion issue. With an empty DATETIME field, I can add a time of 01-01-2014 12:01:02 via Access's datasheet view, if I then look at the value in SQLite the seconds have been rounded off:
sqlite> SELECT three from TEST where FLoc='1020';
2014-01-01 12:01:00.000
SYNCMODE should also be NORMAL not OFF.
Update:
If you have any text fields with a defined length (e.g. foo VARCHAR(10)) and the field contents contains more characters than the field definition (which SQLite allows) MS-Access will also barf when trying to update any of the fields on that row.
I've searched all similar posts as I had a similar issue with SQLite linked via ODBC to Access. I had three tables, two of them allowed edits, but the third didn't. The third one had a DATETIME field and when I changed the data type to a TEXT field in the original SQLite database and relinked to access, I could edit the table. So for me it was confirmed as an issue with the DATETIME field.
After running into this problem, not finding a satisfactory answer, and wasting a lot of time trying other solutions, I eventually discovered that what others have mentioned about DATETIME fields is accurate but another solution exists that lets you keep the proper data type. The SQLite ODBC driver can convert Julian day values into the ODBC SQL_TIMESTAMP / SQL_TYPE_TIMESTAMP types by looking for floating point values in the column, if you have that option enabled in the driver. Storing dates in this manner gives the ODBC timestamp value enough precision to avoid the write conflict error, as well as letting Access see the column as a date/time field.
Even storing sub-second precision in the date string doesn't work, which is possibly a bug in the driver because the resulting TIMESTAMP_STRUCT contains the same values, but the fractional seconds must be lost elsewhere.

UPDATE statement not working in sqlite

I'm using the following command to update a field in my database:
UPDATE Movies SET 'From'=2 WHERE 'Name'="foo";
I'm using sqlite3.exe in windows (command prompt). Although no error message is produced, nothing changes in the table. I examined the database with a couple of gui tools and I'm sure UPDATE does nothing.
'From' is of type integer and 'Name' is text.
The problem you've got is that you're getting your quoting wrong. SQLite follows the SQL standard here, and that specifies what quote characters to use: '…' is for strings, and "…" is for tokens (like special names used as column or table names). Sometimes it manages to guess what you mean anyway and compensate for getting it wrong, but it can't with the WHERE clause because that is syntactically correct (if decidedly unhelpful):
Swapping the quoting appears to work:
UPDATE Movies SET "From"=2 WHERE "Name"='foo';
Those aren't good column names. Both are keywords, best avoided, and not self-explanatory at all.
Do a SELECT to see how many rows match the WHERE clause in the UPDATE. If none come back, you have your answer.
Did you commit the UPDATE? Is auto commit turned on?

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 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