Обычно сортировка SQLite учитывает регистр. Все заглавные буквы идут перед маленькими. Но можно указать SQLite в предложении ORDER BY
игнорировать это, сделав это:
... ORDER BY foo COLLATE NOCASE ASC
Но как это сделать с помощью DBIx :: Class?
Рассмотрим следующий пример, который развертывает базу данных SQLite в памяти с таблицей foo
и одним столбцом bar
. Для подключения используется параметр quote_names
. Он заполняет значения z Z b B a A
, а затем возвращает их, используя all
в ResultSet. Я буду использовать эту настройку во всех следующих примерах. Вам понадобится DBIx :: Class и DBD :: SQLite, чтобы запустить это.
use strict;
use warnings;
package Foo::Schema::Result::Foo;
use base 'DBIx::Class::Core';
__PACKAGE__->table("foo");
__PACKAGE__->add_columns( "bar", { data_type => "text" }, );
package Foo::Schema;
use base 'DBIx::Class::Schema';
__PACKAGE__->register_class( 'Foo' => 'Foo::Schema::Result::Foo' );
package main;
my $schema = Foo::Schema->connect(
{
dsn => 'dbi:SQLite:dbname=:memory:',
quote_names => 1,
}
);
$schema->deploy;
$schema->resultset('Foo')->create( { bar => $_ } ) for qw(z Z b B a A);
my @all = $schema->resultset('Foo')->search(
{},
{
order_by => { -asc => 'me.bar' },
},
)->all;
# example code starts here
print join q{ }, map { $_->bar } @all;
Вывод отсортирован с учетом регистра.
A B Z a b z
Теперь, конечно, я мог бы отсортировать его с помощью Perl и сделать его нечувствительным к регистру, вот так.
print join q{ }, sort { lc $a cmp lc $b } map { $_->bar } @all;
Теперь я получаю
A a B b Z z
Но я также могу использовать COLLATE NOCASE
, если я запрашиваю напрямую с помощью базового дескриптора DBI.
$schema->storage->dbh_do(
sub {
my ( $storage, $dbh, @args ) = @_;
my $res = $dbh->selectall_arrayref(
"SELECT * FROM foo ORDER BY bar COLLATE NOCASE ASC"
);
print "$_->[0] " for @$res;
}
Это дает нам
a A b B z Z
Я хочу, чтобы DBIC использовал COLLATE NOCASE
, но без выполнения SQL. Я не хочу делать дорогостоящие преобразования строк в ORDER BY
или делать их позже в Perl.
Как мне указать DBIx :: Class использовать COLLATE NOCASE
при заказе с помощью SQLite?
Следующее не работает:
order_by => { '-collate nocase asc' => 'me.bar' },
И это работает, только если quote_names
не включен.
order_by => { -asc => 'me.bar COLLATE NOCASE' },
Он выдаст этот запрос и сообщение об ошибке с приведенным выше примером кода.
ВЫБЕРИТЕ "меня". "Bar" ОТ "foo" "me" ЗАКАЗАТЬ "me". "Bar COLLATE NOCASE" ASC: DBIx :: Class :: Storage :: DBI :: _ prepare_sth (): DBI Exception: DBD :: Ошибка SQLite :: db prepare_cached: такого столбца нет: me.bar COLLATE NOCASE [для оператора "SELECT" me "." Bar "FROM" foo "" me "ORDER BY" me "." Bar COLLATE NOCASE "ASC"]
Или я мог бы сделать это, преобразовав в upper
или lower
в предложении ORDER BY
с помощью DBIC.
my @all = $schema->resultset('Foo')->search(
{},
{
order_by => { -asc => 'lower(me.bar)' },
},
)->all;
print join q{ }, map { $_->bar } @all;
Это дает
a A b B z Z
без quote_names
, что похоже, но наоборот. (Это меня не касается), но также выдает ошибку при включении quote_names
.
ВЫБЕРИТЕ "меня". "Bar" ОТ "foo" "me" ORDER BY "lower (me". "Bar)" ASC: DBIx :: Class :: Storage :: DBI :: _ prepare_sth (): DBI Exception: DBD: : SQLite :: db prepare_cached не удалось: такого столбца нет: lower (me.bar) [для утверждения "SELECT" me "." Bar "FROM" foo "" me "ORDER BY" lower (me "." Bar) "ASC "]
order_by => \'me.bar COLLATE NOCASE ASC'
. FWIW, это тоже работает:order_by => { -asc => \'me.bar COLLATE NOCASE' }
. - person Matt Jacob   schedule 03.01.2017