CakePHP - 构建复杂查询

时间:2011-11-23 11:48:22

标签: php sql cakephp

我想使用CakePHP构建以下查询。我应该怎么做呢?

        SELECT
            `Artist`.`id`,
            CONCAT_WS(' ', `Person`.`first_name`, `Person`.`last_name`, `Person`.`post_nominal_letters`) AS `name`,
            `Portfolio`.`count`
        FROM
            `people` as `Person`,
            `artists` as `Artist`
        LEFT OUTER JOIN
            (SELECT
                `Product`.`artist_id`,
                 COUNT(DISTINCT `Product`.`id`) AS `count`
            FROM
                `product_availabilities` AS `ProductAvailability`,
                `products` AS `Product`
            LEFT OUTER JOIN
                `order_details` AS `OrderDetail`
            ON
                `Product`.`id` = `OrderDetail`.`product_id`
            LEFT OUTER JOIN
                `orders` AS `Order`
            ON
                `Order`.`id` = `OrderDetail`.`order_id`
            WHERE
                `ProductAvailability`.`id` = `Product`.`product_availability_id`
            AND
                `Product`.`online` = true
            AND
                (`ProductAvailability`.`name` = 'For sale')
                OR
                    ((`ProductAvailability`.`name` = 'Sold') AND (DATEDIFF(now(),`Order`.`order_date`) <= 30))
            GROUP BY
                `Product`.`artist_id`)
        AS
            `Portfolio`
        ON
            `Artist`.`id` = `Portfolio`.`artist_id`
        WHERE
            `Artist`.`person_id` = `Person`.`id`
        AND
            `Artist`.`online` = true
        GROUP BY
            `Artist`.`id`
        ORDER BY
            `Person`.`last_name`, `Person`.`first_name`;

4 个答案:

答案 0 :(得分:1)

我认为该模型是艺术家并且它与belongsTo有关系,那么你可以用这种方式使用CakePHP ORM并且hasMany with Portfolio

首先,你要破坏艺术家与作品集之间的关系

$this->Artist->unbindModel(array('hasMany'=>array('Portfolio')));

然后建立关系

$this->Artist->bindModel(array('hasOne'=>array('Portfolio')));

最后,您必须创建其他关系

$this->Artist->bindModel(array(
'belongsTo'=>array(
'Product'=>array(
 'clasName'=>'Product',
 'foreignKey'=> false,
 'conditions'=>'Product.id = Artist.product_id'
 ),
 'ProductAvaibility'=>array(
 'clasName'=>'ProductAvaibility',
 'foreignKey'=> false,
 'conditions'=>'ProductAvaibility.id = Product.product_avaibility_id'
 ),
 'OrderDetail'=>array(
 'clasName'=>'OrderDetail',
 'foreignKey'=> false,
 'conditions'=>'Product.id = OrderDetail.product_id'
 ),
 'Order'=>array(
 'clasName'=>'Order',
 'foreignKey'=> false,
 'conditions'=>'Order.id = OrderDetail.order_id'
 ),
)
));

现在,当关系完成后,您可以进行查找

$this->Artist->find('all', array(
'conditions'=>array(
'Artist.online'=>true
),
'group'=>array(
'Artist.id'
),
'order'=>array(
'Person.last_name', 
'Person.first_name', 
)
))

我希望它对你有用

答案 1 :(得分:0)

您应该将它放在模型中。如果您还没有阅读,我建议您阅读skinny controllers and fat models

class YourModel extends AppModel {

    public function getArtistsAndPortfolioCounts() {
        return $this->query("SELECT ... ");
    }

}

所以在你的控制器中:

class ArtistsControllre extends AppController {
    public function yourAction() {
        debug($this->YourModel->getArtistsAndPortfolioCounts());
    }
}

答案 2 :(得分:0)

您可以使用query方法,但当find或任何其他便利方法不够时,该方法将被视为最后的手段。

但也可以在Cake find方法see the cookbook中手动指定联接。我不完全确定,但我相信也支持嵌套连接。可以使用相关字段在find方法的CONCAT_WS属性中调用field

答案 3 :(得分:0)

不要尝试使用ORM构建该查询。这将是一场慢动作的灾难。

相反,你应该尝试尽可能“接近金属”。我不熟悉CakePHP的API(因为我倾向于像黑瘟一样避免它),但你应该能够创建一个与ActiveRecord无关的Model,并且很可能可以访问类似于PDO包装器的任何内容。用它来执行查询并将结果映射到变量。


那就是说,你可能想检查你的查询(你似乎有一些强迫性的引用疾病)。您可以做的一项改进是停止在表中使用id列。

这整个设置确实可以从Artists表中另一列的创建中受益:portfolio_size。每次更改时都可以更新。是的,它会使你的桌子不规范化,但它也会使这个查询变得微不足道并且快速,而其他地方的成本很低。


对于列的名称,如果表Artists具有ID,则将其保留在列artist_id中,如果Products具有引用Artists.artist_id的外键,则将其命名为artist_id。同样的事情应该在整个数据库中具有相同的名称。这还可以让你在SQL USING语句中使用。这是一个小例子:

SELECT 
   Users.name
   Users.email
FROM Users
LEFT JOIN GroupUsers USING (user_id)
LEFT JOIN Groups USING (group_id)
WHERE Groups.name = 'wheel'

我认为此查询不需要解释,因为它是用户和组之间的简单多对多关系。