Как отсортировать текст в sqlite3 с указанным языком?
-
03-07-2019 - |
Вопрос
Sqlite3 по умолчанию сортирует только по буквам ascii. Я попытался заглянуть в Google, но единственное, что я нашел, это информация о сопоставлениях. Sqlite3 имеет только сопоставления NOCASE
, RTRIM
и BIARY
. Как добавить поддержку для конкретной локали?
(Я использую его в приложении Rails)
Решение
SQLite поддерживает интеграцию с ICU . Согласно файлу Readme,
<Код> SQLite / внутр / СИС / 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
Другие советы
Я принял ответ Дуга Карри, но хочу добавить некоторый "алгоритм" как это сделать, потому что документация sqlite3 очень странная (по крайней мере для меня). Р>
Хорошо, у нас есть работающий sqlite3 и теперь:
<Ол>Скомпилируйте его:
gcc -shared icu.c `icu-config --ldflags` -o libSqliteIcu.so
Это для Linux. Мне также нужно было установить дополнительный пакет разработки ICU:
sudo apt-get install libicu-dev
Я работаю над 64-битной архитектурой и получаю сообщение об ошибке с __location 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;
И это без учета регистра!
Если вы не можете позволить себе скомпилировать расширение 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');
Я не ожидаю, что этот подход будет столь же эффективным, как собственное расширение, но он, безусловно, более переносим.
Для тех, кто не может создать расширение самостоятельно, я сделал скомпилированные версии для MacOS и Linux здесь: http://files.tempel.org/Various/Sqlite3ICUExtention
Версии Linux для 32-разрядной и 64-разрядной систем Intel были построены на Ubuntu 16, если это имеет значение.
Как правило, вы не должны доверять скомпилированному коду, предоставленному другими, но я довольно публичный человек, то есть я бы очень рисковал, если бы предоставил " плохой " версия. И чтобы убедиться, что на моем сервере не было ни атаки, ни взлома посредником, вот хеш MD5 для 3 файлов:
libSqliteIcu-i386.so = 6decd73f27d9c61243128e798304508f
libSqliteIcu-x86_64.so = b127c8a1f65503c91c61a21732eb11be
sqlite3_icu_extension.dylib = a29d59f6b74e7ef234691729b82da660