Using COLLATE on peewee queries - sqlite

I found in the peewee documentation how to create custom collations, but I wasn't able to find how to use the built-in sqlite collating sequences.
Ho do I create the following query in peewee (it is the last one in the above mentioned sqlite documentation page)?
SELECT x FROM t1 ORDER BY c COLLATE NOCASE, x;
And how do I specify the collation for an index?
CREATE INDEX i1 ON t1(f1 COLLATE NOCASE);
EDIT
The answer from coleifer addresses the question about the query.
For the index creation I am using the following trick, which works well when you create the indexes only once at startup (like in my app).
The case insensitive unique index on two columns on the table LockedFiles prevents duplicated entries.
class LockedFiles(PeeweeModel):
folder = peewee.CharField(index=True)
file = peewee.CharField(index=True)
#classmethod
def custom_init(cls):
db.execute_sql('create unique index if not exists lockedfiles_unique '
'on lockedfiles(folder collate nocase, file collate nocase)', {})
def create_tables(drop_existing_tables):
for table in [LockedFiles, Model2, Model3]:
if drop_existing_tables:
table.drop_table(True)
table.create_table(True)
try:
table.custom_init()
except:
pass
create_tables(drop_existing_tables=False)

You can specify a collation by building up the SQL clause and passing it to order_by().
For example:
collated = Clause(MyModel.field, SQL('COLLATE NOCASE'))
MyModel.select().order_by(collated, MyModel.other_field)
For the index unfortunately you will need to create that by hand as peewee does not know how to add collation information to the CREATE INDEX SQL. If you'd like to open a pull-request I would definitely consider merging that feature, though.

Related

How to use collation for pattern matching in sqlite?

For example if in the sqlite database have entries Resume, Résumé ,RESUME and if we enter
select Name from NAME_TABLE where Name like 'Re%%'
It should return all
But like does not support collation , any-other way to do pattern matching using collation ?
In SQLite, LIKE always uses the NOCASE or BINARY collations.
You could redefine LIKE by install a user-defined like() function, but you could just as well use your own function with a different name.

Indexes with custom collations in sqlite

Assuming I have a schema like this:
CREATE TABLE abc(
id INTEGER PRIMARY KEY AUTOINCREMENT,
txt TEXT
);
CREATE INDEX "txtCS" ON "abc"("txt" COLLATE MY_CUSTOM_SORT);
when will sqlite use my index on txt ?
because I ran:
EXPLAIN QUERY PLAN SELECT * FROM abc ORDER BY txt COLLATE MY_CUSTOM_SORT DESC ...
and it tells me that it scans the table, twice, using the txtCS index (It doesn't search like I expected.)
MY_CUSTOM_SORT is my own sorting function that I hooked with sqliteCreateCollation. I just need that index for some queries that involve special ordering and I want them to be fast
In the EXPLAIN QUERY PLAN output, SEARCH means that the database tries to look up some particular record(s) with specific values, while SCAN means that the database goes through the entire table.
This query returns all records, so the most efficient operation is a SCAN.
Either operation can be sped up with an index.
(In a SCAN, the database just goes through all index entries in order.)

Cannot resolve the collation conflict?

I had this error and I don't know how to fix it
Cannot resolve the collation conflict between "Arabic_CI_AS" and
"SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
note: I already change the collation from the database option --> Collation
I change it from "Arabic_CI_AS" to "SQL_Latin1_General_CP1_CI_AS"
and I am still getting the same error !!
Any suggestion to solve this ?
The database collation applies only when you create NEW objects without specifying the collation.
When you change it from "Arabic_CI_AS" to "SQL_Latin1_General_CP1_CI_AS", all the textual columns in the database are still collated Arabic_CI_AS. You can check this using
select object_name(object_id), name, collation_name
from sys.columns
where collation_name like '%Arabic%'
A patch to this problem is to put COLLATE DATABASE_DEFAULT against the comparison, e.g.
SELECT *
FROM TBL1
INNER JOIN TBL2 on X = Y COLLATE DATABASE_DEFAULT
or
SELECT *
FROM TBL1
WHERE X = Y COLLATE DATABASE_DEFAULT
etc
There is a script on this site that attempts to change the collation across an entire database, but
I have not personally tried it
Make sure you have a good backup of your database before trying it
It doesn't look like it will handle complex databases with indexed views, foreign key/default constraints etc

Syntax for using collate nocase in a SQLite replace function

I have an existing database where they created theiw own unicode collation sequence. I'm trying to use the following code and get a "no such collation sequence" exception. Can anybdy hlep with the the syntax to use "collate nocase" with this code?
update Songs set
SongPath = replace (SongPath, 'Owner.Funkytown', 'Jim');
Dump database (via shell), edit output SQL (find and change column definitions, set COLLATION NOCASE). Recreate database.

SQLITE: Unable to remove an unnamed primary key

I have a sqlite table that was originally created with:
PRIMARY KEY (`column`);
I now need to remove that primary key and create a new one. Creating a new one is easy, but removing the original seems to be the hard part. If I do
.indices tablename
I don't get the primary key. Some programs show the primary key as
Indexes: 1
[] PRIMARY
The index name is typically in the [].
Any ideas?
You can't.
PRAGMA INDEX_LIST('MyTable');
will give you a list of indices. This will include the automatically generated index for the primary key which will be called something like 'sqlite_autoindex_MyTable_1'.
But unfortunately you cannot drop this index...
sqlite> drop index sqlite_autoindex_MyTable_1;
SQL error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
All you can do is re-create the table without the primary key.
I the database glossary; a primary-key is a type of index where the index order is typically results in the physical ordering of the raw database records. That said any database engine that allows the primary key to be changed is likely reordering the database... so most do not and the operation is up to the programmer to create a script to rename the table and create a new one. So if you want to change the PK there is no magic SQL.
select * from sqlite_master;
table|x|x|2|CREATE TABLE x (a text, b text, primary key (`a`))
index|sqlite_autoindex_x_1|x|3|
You'll see that the second row returned from my quick hack has the index name in the second column, and the table name in the third. Try seeing if that name is anything useful.

Resources