【问题标题】:CakePHP - Virtual field issue using Paginator HelperCakePHP - 使用 Paginator Helper 的虚拟字段问题
【发布时间】:2013-12-23 04:04:38
【问题描述】:

我有一个包含纬度/经度字段的列表表。我正在使用Haversine Formula 计算原点(33.987339、-81.036819)和每个列表的纬度/经度之间的 距离(作为别名/虚拟字段),并返回列表距离起点 10 英里以内的距离

phpMyAdmin 中的以下 SQL 查询完全符合我的预期:

SELECT *, round(3959 * acos(cos(radians(33.987339)) * cos(radians(Listing.lat)) * cos(radians(Listing.long) - radians(-81.036819)) + sin( radians(33.987339)) * sin(radians(Listing.lat)))) 
AS distance, `Listing`.`id` 
FROM `preview_site`.`listings` AS `Listing` 
LEFT JOIN `preview_site`.`users` AS `User` ON (`Listing`.`user_id` = `User`.`id`) 
LEFT JOIN `preview_site`.`categories` AS `Category` ON (`Listing`.`category_id` =   `Category`.`id`) 
LEFT JOIN `preview_site`.`states` AS `State` ON (`Listing`.`state_id` = `State`.`id`) 
WHERE `Listing`.`status` = 'Active' 
HAVING distance < 10 
ORDER BY `distance` ASC LIMIT 20

在尝试(并以多种方式失败)让 CakePHP 代码正确生成上述 SQL 之后,我使用 this tool 从 SQL 生成以下 CakePHP 控制器代码(它提供了模型和控制器选项):

$this->Paginator->virtualFields = array(
'distance' => 'round(3959 * acos(cos(radians(33.987339)) * cos(radians(Listing.lat )) * cos(radians(Listing.long) - radians(-81.036819)) + sin(radians(33.987339)) * sin(radians(Listing.lat))))');
$this->Paginator->settings = array(
'fields' => array(
    'Listing.*',
    'Listing.distance',
    'Listing.id',
    'Category.*',
    'State.*',
    'User.*',
),
'joins' => array(

    array(
        'conditions' => array(
            'Listing.user_id = UserJoin.id',
        ),
        'table' => 'users',
        'alias' => 'UserJoin',
        'type' => 'left',
    ),
    array(
        'conditions' => array(
            'Listing.category_id = CatJoin.id',
        ),
        'table' => 'categories',
        'alias' => 'CatJoin',
        'type' => 'left',
    ),
    array(
        'conditions' => array(
            'Listing.state_id = StateJoin.id',
        ),
        'table' => 'states',
        'alias' => 'StateJoin',
        'type' => 'left',
    ),
),
'conditions' => array(
    'Listing.status' => 'Active',
),
'order' => array(
    'distance' => 'asc',
),
'limit' => '5',
'having' => array(
    'distance <' => '10',
),
'contain' => array(
    'User',
    'Category',
    'State',
),
);
$data = $this->Paginator->paginate('Listing');
$this->set('listings', $data);

如果我使用此代码,我会收到以下错误:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Listing.distance' in 'field list'

如果我将 $this->Paginator->virtualFields 更改为 $this->Listing->virtualFields(因为我找不到任何关于 Paginator 的文档实际上使用virtualFields 方法),我没有收到任何错误并且分页工作正常,但返回的结果不受距离限制(返回所有列表记录)。这是生成的 SQL 的 sn-p 与距离别名:

SELECT `Listing`.*, `Listing`.`id`, `Category`.*, `State`.*, `User`.*, (round(3959 *  acos(cos(radians(33.987339)) * cos(radians(`Listing`.`lat` )) *  cos(radians(`Listing`.`long`) - radians(-81.036819)) + sin(radians(33.987339)) *  sin(radians(`Listing`.`lat`))))) 
AS `Listing__distance` 
FROM `preview_site`.`listings` AS `Listing` 

是否有人对如何使这项工作正常工作有任何建议?任何帮助将不胜感激。

【问题讨论】:

    标签: mysql cakephp pagination alias


    【解决方案1】:

    有很多关于虚拟领域的公开票。 这很可能就是其中之一。

    即使您与分页器的初始绑定看起来不正常。 您应该将虚拟字段添加到当前模型中,以便列出。

    $this->Listing->virtualFields['distance'] = ...
    

    对我来说,在那些我不能轻易使用虚拟字段的情况下,它有助于手动使用别名字段,所以 Listing__distance ASC 在您的订单中或更重要的是在您的 having 子句中。 它还将重用已经计算的字段,而不是再次执行(即使我不知道这种方式是否有速度提升)。见this

    另请注意,利用behavior 避免对其他查询重复该操作(并使其保持干燥)可能更简洁:

    $this->Listing->setDistanceAsVirtualField($lag, $lng);
    

    而且我通常使用条件来限制距离(不需要有,是吗?)。

    【讨论】:

    • 你是对的,不需要Have,它作为一个条件可以正常工作。我会考虑在未来使用一种行为。谢谢您的答复!如果这是 Reddit,我会给你和凯金 :)
    【解决方案2】:

    我认为您的问题出在哪里,我相信 CakePHP 无法识别“Having”。由于您似乎没有 Group By,因此您可以使用常规 WHERE 并获得相同的结果,在这种情况下,array('conditions' =&gt; array('distance &lt;' =&gt; 10)) 如果您确实有 Group By,请参阅以下内容:

    CakePHP: How can I use a "HAVING" operation when building queries with find method?

    【讨论】:

    • 哈!在此过程的早期,我确实在“Group by”行中进行了“Having”操作,但是当我删除“Group by”时,我没有意识到我可以将它与其他 WHERE 条件一起添加。我在那里添加了它,现在它可以正常工作了,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多