繁体   English   中英

如何使用SQLite使ORDER BY中的DBIx :: Class忽略大小写?

[英]How do I make DBIx::Class ignore case in ORDER BY with SQLite?

通常,SQLite的排序规则区分大小写。 所有大写字母都在小写字母之前。 但是有可能通过这样做告诉SQLite在ORDER BY子句中忽略它:

... ORDER BY foo COLLATE NOCASE ASC

但是我们如何用DBIx :: Class做到这一点?

请考虑以下示例,该示例使用表foo和一个comlumn bar在内存中部署SQLite数据库。 连接使用quote_names设置 它填充值z Z b B a A ,然后使用ResultSet上的all将它们返回。 我将在以下所有示例中使用此设置。 你需要DBIx :: ClassDBD :: 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”me“。”bar COLLATE NOCASE“ASC”]

或者我可以通过使用DBIC在ORDER BY子句中转换为upperlower来实现。

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 (这不是我关心的问题),但是当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 “]

如果您习惯使用非常少量的SQL,则可以传递标量引用来表示文字SQL,并且DBIC不会弄乱它:

order_by => \'me.bar COLLATE NOCASE ASC'

或者,只使用最少量的文字SQL:

order_by => { -asc => \'me.bar COLLATE NOCASE' }

请注意,这种语法在技术上不鼓励的 ,但我不知道有任何其他方法可以实现您的目标:

尽管强烈建议您使用上面概述的hashref语法,但仍支持旧的scalarref语法(即order_by => \\'year DESC')。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM