Как отсортировать текст в sqlite3 с указанной локалью?
Sqlite3 по умолчанию сортирует только буквы ascii. Я попытался посмотреть в Google, но единственное, что я нашел, это информация о сортировках. Sqlite3 имеет только NOCASE
, RTRIM
и BIARY
сопоставления. Как добавить поддержку для определенной локали?
(Я использую его в приложении Rails)
Ответы
Ответ 1
SQLite поддерживает интеграцию с ICU, Согласно файлу Readme,
sqlite/ext/icu/README.txt
каталог sqlite/ext/icu/
содержит исходный код расширения SQLite "ICU",
интеграция библиотеки "Международные компоненты для Unicode" с SQLite.
1. Features
1.1 SQL Scalars upper() and lower()
1.2 Unicode Aware LIKE Operator
1.3 ICU Collation Sequences
1.4 SQL REGEXP Operator
Ответ 2
Я принял ответ Doug Currie, но я хочу добавить "алгоритм", как это сделать, потому что документация sqlite3 очень странная (по крайней мере, для меня).
Хорошо, у нас есть рабочий sqlite3 и теперь:
-
Загрузить расширение ICU для sqlite
-
Скомпилируйте его:
gcc -shared icu.c `icu-config --ldflags` -o libSqliteIcu.so
Это для Linux. Мне также необходимо установить дополнительный пакет разработки ICU:
sudo apt-get install libicu-dev
Я работаю над 64-битной архитектурой, и я получаю ошибку с __relocation R_X86_64_32S__
(что бы это ни значило:). GCC предложил добавить -fPIC
для компиляции параметров, и это помогло.
-
Запустите sqlite3. Мы можем загрузить расширение командой:
.load './libSqliteIcu.so'
Предполагая, что он находится в текущем каталоге, мы также можем указать весь путь.
-
Создать новую сортировку:
SELECT icu_load_collation('pl_PL', 'POLISH');
Первый параметр - желаемый язык, а второй - это (он может быть любым).
-
Теперь мы можем сортировать данные с нашей новой локалью:
SELECT * FROM some_table ORDER BY name COLLATE POLISH;
И это нечувствительно к регистру!
Ответ 3
Если вы не можете позволить себе скомпилировать расширение ICU, вы можете сделать UDF так же. В PHP/PDO:
$pdo->sqliteCreateFunction('locale',
function ($data, $locale = 'root')
{
static $collators = array();
if (isset($collators[$locale]) !== true)
{
$collators[$locale] = new \Collator($locale);
}
return $collators[$locale]->getSortKey($data);
}
);
Пример использования:
SELECT * FROM "table" ORDER BY locale("column", 'pt_PT');
Я не ожидаю, что такой подход будет таким же эффективным, как родное расширение, но он, безусловно, более портативен.
Ответ 4
Для тех, кто не может создать расширение самостоятельно, я сделал скомпилированные версии для MacOS и Linux здесь: http://files.tempel.org/Various/Sqlite3ICUExtention
Версии Linux для Intel 32 и 64-битной версии были построены на Ubuntu 16, если это имеет значение.
Как правило, вы не должны доверять скомпилированному коду, предоставленному другими, но я довольно публичный человек, то есть я бы рискнул, если бы предоставил "плохую" версию. И чтобы убедиться, что на моем сервере не было ни атаки, ни взлома посредником, вот хеш MD5 для 3 файлов:
libSqliteIcu-i386.so = 6decd73f27d9c61243128e798304508f
libSqliteIcu-x86_64.so = b127c8a1f65503c91c61a21732eb11be
sqlite3_icu_extension.dylib = a29d59f6b74e7ef234691729b82da660