尽可能抽象,我想表演:
select id,complicatedCalculation as geodistance from User join others having geodistance < 100;
在 CakePHP 2.x 中。实际查询使用聚合,因此我们确实需要having。当数据库是 MySQL 时,这一切都有效,因为该数据库接受 having 子句中的列引用。我们现在正在转向 Postgres,它更严格地实现 SQL 标准并报告
geodistance
不存在。
SQL 中的解决方案是将指令写为
select * from (select id, complicatedCalculation as geodistance from User join others) as sub where geodistance < 100;
但是我不知道如何在 Cake 中表达该子查询。迄今为止我最好的尝试是
$db = $this->User->getDataSource();
$core = [ 'fields' => [ 'id', 'complicatedCalculation as geodistance' ],
'table' => $db->fullTableName($this->User),
'join' => (others) ]
$sub_query = $db->buildStatement($core, $this->User);
$result = $this->User->find('all', [
'fields' => [ 'id', 'geodistance' ],
'table' => $db->expression($sub_query),
'alias' => 'zzz', // not used but PGSQL requires it.
'conditions' => [ 'geodistance <=' => 100 ]
]);
但这会产生以下 SQL(抽象),在日志中报告为错误:
SELECT "User"."id" AS "User__id", complicatedCalculation as geodistance FROM "public"."users" AS "User" LEFT JOIN (others) WHERE "geodistance" <= 100
所以我尝试让 CakePHP 使用表达式作为表是行不通的。我可以让它这样做吗?
建议升级到当前版本的 Cake 的答案不可接受。如果没有其他办法,我们就使用
query()
。
两者都不是更好。可能他们会以完全相同的方式被处决。来看看
EXPLAIN SELECT ...
真正的问题是必须计算每一行的
geodistance
,并且没有简单的方法可以加快速度。
这里有5种方法
;你的相当于第一个(最差的):查找最近的.
更好的是使用
SPATIAL
索引。这将需要改变数据的存储方式。
另一个相当不错的方法是建立一个“边界框”,然后有2个索引。
该链接中讨论了两种替代方案。
您的查询是“查找 100 以内的所有内容”。该链接谈到“找到 100 内最接近的 N”。