2011-11-23 140 views
4

我有我想要使用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`; 

回答

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()); 
    } 
} 
+1

「Model :: query()'方法是否是最好的方法? – freshest

+0

我這麼認爲,因爲這種方式可以緩存,並且返回的結果與$ this-> find()相近。 – gustavotkg

+1

你可以使用子查詢來做到這一點,這會不會更好的代碼維護? – freshest

0

你可以使用query方法,但該方法被視爲最後的手段,當find或任何其他方便的方法是不夠的。

但也可以在Cake find方法see the cookbook中手動指定連接。我不完全確定,但我相信也支持嵌套連接。 CONCAT_WS只能在find方法的field屬性中與相關字段一起調用。

+1

CakePHP 2.0具有虛擬字段,您可以在其中指定任何SQL作爲該字段,包括子查詢和CONCAT_WS – gustavotkg

+0

如果您想使用「虛擬字段」,則它們也存在於Cake 1.3中:http://book.cakephp。 org/view/1608/Virtual-fields – mensch

+0

當然,你不能使用virtualFields爲每個Artist獲取'Portfolio.count'? – freshest

0

不要嘗試使用ORM構建該查詢。這將是一場慢動作的災難。

相反,您應該嘗試儘可能做到「接近金屬」。我不熟悉CakePHP的API(因爲我傾向於避免它像黑色瘟疫),但你應該能夠創建一個與ActiveRecord無關的Model,並且最有可能訪問與PDO包裝類似的任何東西。用它來執行查詢並將結果映射到變量。


這就是說,你可能要檢查你的查詢(你似乎有一些強迫報價病)。你可以做的一個改進就是停止在表格中使用id列。

這整個設置可以真正受益於創建藝術家表中的另一列: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' 

我認爲這個查詢不需要解釋,因爲它是用戶和組之間的簡單許多一對多的關係。

1

我認爲,該模型是藝術家和它有一個屬於關聯關係,那麼你可以在這條路上使用CakePHP的ORM和的hasMany與投資組合

首先你每畝distroy藝術家和投資組合

之間的關係

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

,然後建立關係

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

最後,你必須創建其他relationsships

$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', 
) 
)) 

我希望它對你有用