我正在尝试使用DBIx :: Class进行外围搜索,但到目前为止还没有成功。
我想生成的SQL如下所示:
SELECT
zip,
6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(USERLAT)) * Cos(RADIANS(USERLNG) - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(USERLAT)) ) AS Distance
FROM
geopc
WHERE
6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(USERLAT)) * Cos(RADIANS(USERLNG) - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(USERLAT)) ) <= DISTANCE
ORDER BY
Distance
其中USERLAT,USERLNG和DISTANCE应该是变量,它们将通过Webrequest进行。
我的DBIx ::类结果:
use utf8;
package MyApp::Models::Schema::Result::Geopc;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table("geopc");
__PACKAGE__->add_columns(
"id",
{ data_type => "bigint", is_nullable => 0, is_auto_increment => 1 },
"country",
{ data_type => "varchar", is_nullable => 0, size => 2 },
"language",
{ data_type => "varchar", is_nullable => 0, size => 2 },
"iso2",
{ data_type => "varchar", is_nullable => 0, size => 6 },
"region1",
{ data_type => "varchar", is_nullable => 0, size => 60 },
"region2",
{ data_type => "varchar", is_nullable => 0, size => 60 },
"region3",
{ data_type => "varchar", is_nullable => 0, size => 60 },
"region4",
{ data_type => "varchar", is_nullable => 0, size => 60 },
"zip",
{ data_type => "varchar", is_nullable => 0, size => 10 },
"city",
{ data_type => "varchar", is_nullable => 0, size => 60 },
"area1",
{ data_type => "varchar", is_nullable => 0, size => 80 },
"area2",
{ data_type => "varchar", is_nullable => 0, size => 80 },
"lat",
{ data_type => "double precision", is_nullable => 0 },
"lng",
{ data_type => "double precision", is_nullable => 0 },
"tz",
{ data_type => "varchar", is_nullable => 0, size => 30 },
"utc",
{ data_type => "varchar", is_nullable => 0, size => 10 },
"dst",
{ data_type => "varchar", is_nullable => 0, size => 1 },
);
__PACKAGE__->set_primary_key('id');
我用谷歌搜索过,但还没有找到一个好方法来解决这个问题。非常感谢任何帮助。
我正在使用MySQL ......
答案 0 :(得分:1)
此类复杂查询的一个解决方案是将它们定义为view。如果您定义与它的关系,那么它具有加入和预取的优势。
另一个使用columns计算“距离”列的人。 'columns'只是'select'和'as'参数的组合,已被证明是一个更强大的api,可以减少用户错误。 请注意,搜索语法来自SQL::Abstract,它提供了一些使用literal sql的方法。
没有子查询的最佳解决方案是:
my $param = \[
'6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(?)) * Cos(RADIANS(?)' .
' - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(?)) )'
[ USERLAT => $USERLAT ],
[ USERLNG => $USERLNG ],
[ USERLAT => $USERLAT ],
];
my $geopc = $schema->resultset('Result::Geopc')->search({
$param => { '<=', $distance },
}, {
columns => [
'zip',
{ distance => $param }
],
order_by => $param,
});
答案 1 :(得分:1)
我遇到了同样的问题:companies
belongs_to
address
,has_many
companies
,地址Adress
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"country",
{ data_type => "varchar", is_nullable => 0, size => 64 },
"county",
{ data_type => "varchar", is_nullable => 1, size => 45 },
"city",
{ data_type => "varchar", is_nullable => 0, size => 64 },
"street",
{ data_type => "varchar", is_nullable => 0, size => 128 },
"street_no",
{ data_type => "varchar", is_nullable => 1, size => 24 },
"apartment_no",
{ data_type => "varchar", is_nullable => 1, size => 24 },
"extra",
{ data_type => "varchar", is_nullable => 1, size => 128 },
"lat",
{ data_type => "decimal", is_nullable => 1, size => [10, 7] },
"long",
{ data_type => "decimal", is_nullable => 1, size => [10, 7] },
);
- 我需要找到邻居公司,所以,使用get_neighbour_companies
模型:
sub get_neighbour_companies{
my ( $self, $args ) = @_;
my $distance = $args->{distance} // 15;
my $geo_clause = sprintf('( 6371 * acos( cos( radians(%s) ) * cos( radians( me.lat ) ) * cos( radians( me.`long` ) - radians(%s) ) + sin( radians(%s) ) * sin( radians( me.lat ) ) ) ) AS distance', $self->lat, $self->long, $self->lat );
my $rs = $self->result_source->schema->resultset('Address')
->search_rs(
{
'companies.company_type_id' => ( $args->{company_type_id} // 1 ), #defaults to 'orderer' type
},
{
prefetch => { 'companies' => 'address' },
select => [ 'id', \$geo_clause ],
as => [qw/ id distance /],
having => { distance => { '<=' => $distance } },
order_by => 'distance',
}
);
my @companies;
while ( my $address = $rs->next ){
my @comps = $address->companies()->all;
next unless @comps;
foreach my $company ( @comps ) {
push @companies, {
company => $company,
distance => $address->get_column('distance'),
};
}
};
return [ @companies ];
}
我在该模型中实现了方法my $customers = $comp->address->get_neighbour_companies({
distance => 12,
company_type_id => 1,
});
:
$customers
我正在使用它:
companies
其中$comp
将是company
的{{1}}列表中的数组引用{{1}},也是{{1}}
答案 2 :(得分:0)
您可以重写查询以使用如下子查询:
SELECT zip, Distance
FROM (SELECT zip,
6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(USERLAT)) * Cos(RADIANS(USERLNG) - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(USERLAT)) )
AS Distance
FROM geopc) AS tmp
WHERE Distance <= DISTANCE
ORDER BY Distance
然后类似下面的内容应该有效:
my $geopc = $schema->resultset('Result::Geopc');
my $subquery = $geopc->search({}, {
select => [
'zip',
\[
'6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(?)) * Cos(RADIANS(?)' .
' - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(?)) )' .
' AS Distance',
[ USERLAT => $USERLAT ],
[ USERLNG => $USERLNG ],
[ USERLAT => $USERLAT ],
],
],
})->as_query;
my $rs = $geopc->search({
Distance => { '<=' => $DISTANCE },
}, {
alias => 'geopc2',
from => [
{ geopc2 => $subquery },
],
select => [ qw(zip Distance) ],
order_by => 'Distance',
});
此方法使用literal SQL with placeholders和未记录的ResultSet属性from
。可以在DBIx::Class test suite中找到from
属性的一些用法示例。请注意,由于此属性未记录,因此在将来的版本中可能不支持该属性。