通常,SQLite的排序规则区分大小写。所有大写字母都在小写字母之前。但是有可能告诉SQLite在ORDER BY
子句中忽略它,by doing this:
... ORDER BY foo COLLATE NOCASE ASC
但是我们如何用DBIx :: Class做到这一点?
考虑以下示例,该示例使用表foo
和一个comlumn bar
在内存中部署SQLite数据库。该连接使用the quote_names
setting。它填充值z Z b B a A
,然后使用ResultSet上的all
将它们取回。我将在以下所有示例中使用此设置。您需要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
但如果直接使用底层DBI句柄查询,我也可以使用COLLATE NOCASE
。
$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中执行这些转换。
在使用SQLite订购时,如何告诉DBIx :: Class使用COLLATE NOCASE
?
以下不起作用:
order_by => { '-collate nocase asc' => 'me.bar' },
这仅在quote_names
未开启时才有效。
order_by => { -asc => 'me.bar COLLATE NOCASE' },
它将使用上面的示例代码生成此查询和错误消息。
SELECT“me”。“bar”FROM“foo”“me”ORDER BY“me”。“bar COLLATE NOCASE” ASC:DBIx :: Class :: Storage :: DBI :: _ prepare_sth():DBI异常: DBD :: SQLite :: db prepare_cached失败:没有这样的列:me.bar COLLATE NOCASE [for Statement“SELECT”me“。”bar“FROM”foo“”me“ORDER BY “我”。“吧COLLATE NOCASE”ASC“]
或者我可以使用DBIC转换为upper
子句中的lower
或ORDER BY
。
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
开启时也会抛出错误。
SELECT“me”。“bar”FROM“foo”“me”ORDER BY“lower(me”。“bar)”ASC: DBIx :: Class :: Storage :: DBI :: _ prepare_sth():DBI异常: DBD :: SQLite :: db prepare_cached失败:没有这样的列:lower(me.bar) [for Statement“SELECT”me“。”bar“FROM”foo“”me“ORDER BY “lower(me”。“bar”“ASC”]
答案 0 :(得分:4)
如果你习惯使用极少量的SQL,你可以传递一个标量引用来表示文字SQL,而DBIC不会惹它:
order_by => \'me.bar COLLATE NOCASE ASC'
或者,只有最少量的文字SQL:
order_by => { -asc => \'me.bar COLLATE NOCASE' }
请注意,此语法为technically discouraged,但我不知道有任何其他方法可以实现您的目标:
旧的scalarref语法(即order_by => \'年DESC')仍然是 支持,但强烈建议您使用hashref 语法如上所述。