Reputation: 441
I have a SQLite-database with table with a document number following this schema:
16-145-45
16-127-30
16-141-42
16-122-14
15-090-04
15-089-15
15-089-05
I'd like to sort the ResultSet
on the first and last part of the number, like this. First, all documents starting with the highest two-digit prefix (16) sorted by the last 2 digits and then the same with the next block, and so on.
16-145-45
16-141-42
16-127-30
16-122-14
15-089-15
15-089-05
15-090-04
Is there a way to do this in DBIx::Class
with some sort of custom order_by
clause, or what would be the approach?
I have tried the following, which does not work, because the middle part of the number is also considered for sorting:
my @rs = $self->search(undef,
{
order_by => { -desc => 'me.number' }
}
);
Upvotes: 2
Views: 626
Reputation: 33658
If you want the database to sort the results, you have to use literal SQL.
Here's an example for Postgres (I added a space after the backslash to fix the syntax highlighting):
my @rs = $self->search(undef,
{
order_by => \ "split_part(number, '-', 1) || split_part(number, '-', 3) DESC",
}
);
Or, by creating an output column with the +select
result set attribute:
my @rs = $self->search(undef,
{
'+select' => [
{ sort_key => \ "split_part(number, '-', 1) || split_part(number, '-', 3)" },
],
'+as' => [ qw(sort_key) ], # Make sort key accessible from DBIC.
order_by => { -desc => 'sort_key' },
}
);
Another approach is to retreive the whole unsorted result set, and sort it on the client side. DBIC doesn't have any specific features to help you with that, so simply use Perl's sort
function.
Upvotes: 2
Reputation: 126762
You need to extract additional columns from the result set which are equal to the value of the function that you want to sort by. Then you can just put those columns in an order_by
clause as normal
This assumes that your document number field is called docnum
. It fetches all the columns from Table
plus the two substrings of docnum
called docnum1
and docnum3
my $rs = $schema->resultset('Table')->search(undef,
{
'+select' => [
{ substr => [ 'docnum', 1, 2 ], -as => 'docnum1' },
{ substr => [ 'docnum', -2 ], -as => 'docnum3' },
],
order_by => [ { -desc => 'docnum1' }, { -desc => 'docnum3' } ],
}
);
Upvotes: 1
Reputation: 441
Since the answer from @nwellnhof works like a charm, I just wanted to provide the corresponding syntax for SQLite, which does not know the split_part()
function.
# SQL for filtering the doc number in SQLite
my @rs = $self->search(undef,
{
order_by => \ "SUBSTR(me.number, 1, 2) || SUBSTR(me.number, -2, 2) DESC"
}
);
Upvotes: 1