【问题标题】:Translate this monsterous query w/HABTM related data into a CakePHP find将这个带有 HABTM 相关数据的怪物查询翻译成 CakePHP 查找
【发布时间】:2012-01-11 23:15:46
【问题描述】:

已经很晚了,我已经写了这个怪异的查询来根据我已经找到的产品获取相关产品。

我需要获取同一类别(HABTM)中的产品、父产品、具有相同父产品(兄弟/邻居)的产品以及当前产品的直接子产品(只有一层嵌套)。我有当前产品的产品 ID 及其 parent_id。如果可以在产品上设置Product.published = 1 的条件,那就太好了,但如果它会使查询变得如此之大,我总是可以在之后检查。另外,我需要排除当前产品。

SELECT `products`.*
FROM `products`, `categories_products`
WHERE
(
    (
        `categories_products`.`product_id` = `products`.`id`
        AND `categories_products`.`category_id` IN (
            SELECT `category_id`
            FROM `categories_products`
            WHERE `categories_products`.`product_id` = '$product_id'
        )
    )
    OR `products`.`parent_id` = '$parent_id'
    OR `products`.`parent_id` = '$product_id'
    OR `products`.`id` = '$parent_id'
)
AND `product`.`id` <> '$product_id'

GROUP BY `products`.`id`

甚至可以进一步优化它,到目前为止我有:

public function related($productData, $limit = 4) {

    $conditions = array(
        'OR' => array(array('Product.parent_id' => $productData['Product']['id'])), // Children of product),
        'Product.id <>' => $productData['Product']['id']
    );

    if(!empty($product['parent_id'])) {
        $conditions['OR'][] = array('Product.parent_id' => $productData['Product']['parent_id']); // Siblings
        $conditions['OR'][] = array('Product.id' => $productData['Product']['parent_id']); // Parent of product
    }

    return $this->find('all', array(
        'conditions' => $conditions,
        'contain' => array('Category'),
        'group' => 'Product.id',
        'limit' => $limit
    ));
}

【问题讨论】:

  • 可怕吗?这似乎只是一个正常的选择......营销+1
  • @Márcio 关于这个玩笑:)
  • 为了简单起见,我希望这些变量嵌入到查询中?
  • 您必须查看手册的“复杂查找查询”部分,了解如何形成子查询。不过老实说,经过一段时间后,通过 Cake DAL 是不值得的,您应该简单地精心制作自己的 SQL 并使用Model::query
  • 这是一个真正的怪物查询:neilcrookes.com/2009/02/26/get-all-acl-permissions

标签: mysql cakephp join has-and-belongs-to-many


【解决方案1】:

您需要使用 cake 的 Complex Find Conditions syntax(向下滚动到子查询部分)。

【讨论】:

    【解决方案2】:

    说实话,我不认为这是从 mysql 获取“相关”产品的最佳方法,这就是搜索引擎的用途。尤其是在处理大数据时,您的类似类别方法注定会失败。

    说了这么多之后,这是对您当前 sql 的重写,希望您能获得一些性能。

    SELECT * FROM products p
    WHERE 
        p.published = 1 AND 
        p.id != $product_id AND
        (
            p.id IN 
                (
                    SELECT DISTINCT(cp2.product_id) FROM categories_product cp1
                    LEFT JOIN categories_product cp2 ON cp1.category_id = cp2.category_id
                    WHERE cp1.product_id = $product_id
                    UNION SELECT $parent_id
                )
            OR p.parent_id IN($parent_id, $product_id)
        )
    ;
    

    我试图摆脱不必要的 group by 语句。希望这会有所帮助。

    P.S:由于我是在文本编辑器中编写的,因此可能存在语法错误。

    【讨论】:

    • 这个问题的全部目的是将查询放入 CakePHP 查找中,但无论如何谢谢。
    【解决方案3】:

    我会阻止递归尝试在类别上进行 SELECT IN。基于有问题的一种产品进行预构建,并获取其所有不同的类别。由此,获得与该类别相匹配的独特产品。现在,您有一个“CommonByCategory”的预查询,它已经是一个 ID 实例。

    接下来,根据您尝试获得资格的特定 ID,再次对产品“OriginalProduct”进行硬连接。由于它永远存在并且永远不会改变,我们可以使用它作为兄弟姐妹比较的指针,也可以用于父 ID 匹配(如果不为空 - 通过应用的 IFNULL() 测试

    由于每个产品将仅被扫描一次并且由于多个类别的可能性而不会返回多个条目,因此不需要“GROUP BY”。

    SELECT STRAIGHT_JOIN 
          p.*
       from 
          products p
             left join 
                ( SELECT DISTINCT 
                        cp2.product_id
                     from
                        ( SELECT cp.Category_ID
                             from categories_products cp
                             where cp.product_id = '$product_id' ) JustCats
                         join categories_products cp2
                            ON JustCats.Category_ID = cp2.Category_ID ) as CommonByCategory
                ON p.ID = CommonByCategory.product_ID
    
             join products OriginalProduct
                ON OriginalProduct.ID = '$product_id'
    
       where
              p.id <> '$product_id'
          and ( IFNULL( CommonByCategory.Product_ID, -1) > 0
              OR p.id = IFNULL( OriginalProduct.Parent_ID, -1 )
              OR p.parent_id = OriginalProduct.id
    

    【讨论】:

      【解决方案4】:

      这个问题又来了,我100%搞定了!这是我完成的代码:

      // Model
      public function related($product, $limit = 9) {
      
          // Children of product
          $conditions = array(
              'OR' => array(array('Product.parent_id' => $product['Product']['id'])), // Children of product),
              'Product.id <>' => $product['Product']['id'],
              'Product.published' => 1
          );
      
          // Siblings and parent of product if applicable
          if (!empty($product['Product']['parent_id'])) {
      
              $conditions['OR'][] = array('Product.parent_id' => $product['Product']['parent_id']);
              $conditions['OR'][] = array('Product.id' => $product['Product']['parent_id']);
          }
      
          // Products in the same categories
          // Get category IDs in an array
          $categoryIds = Set::extract($product['Category'], '{n}.id');
      
          $conditionsSubQuery['category_id IN(?)'] = implode(',', $categoryIds);
      
          $db = $this->getDataSource();
          $subQuery = $db->buildStatement(
                  array(
              'fields' => array('product_id'),
              'table' => 'categories_products',
              'joins' => array(),
              'alias' => 'c_p',
              'conditions' => $conditionsSubQuery,
              'order' => null,
              'group' => null,
              'limit' => null
                  ), $this->CategoryProduct
          );
          $subQuery = 'Product.id IN (' . $subQuery . ') ';
          $subQueryExpression = $db->expression($subQuery);
      
          $conditions['OR'][] = $subQueryExpression;
      
          return $this->find('all', array(
                      'conditions' => $conditions,
                      'contain' => array('Category'),
                      'group' => 'Product.id',
                      'limit' => $limit
                  ));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-22
        • 1970-01-01
        • 2019-05-09
        • 2015-11-07
        • 1970-01-01
        相关资源
        最近更新 更多