0

另一个需要解释的奇怪问题,在此先感谢您的帮助。

我继承了一个 opencart 安装,并被要求修改一个报告生成器 (Product Export Express),该生成器运行一个大型 MySQL 查询,以输出一个包含所有相关产品信息以及其他数据花絮的 xls 文件。现在我正在使用以下代码:

    <?php
ini_set("memory_limit","1G");   
class ModelInventoryExpress extends Model
{


    public function getProducts(){
        $products_sql = "SELECT
        p.product_id AS             `Product ID`, 
        p.model AS                  `Model`,
        p.sku as                    `SKU`,
        pd.name AS                  `Product Name`,
        cd.name as                  `Category`,
        p.location AS               `Location`,
        p.quantity AS               `Quanity`,
        (SELECT `text` 
        FROM product_attribute pa 
        WHERE pa.product_id = p.product_id 
        AND pa.attribute_id = 6) AS `Box Count`,

        (SELECT `text` 
        FROM product_attribute pa 
        WHERE pa.product_id = p.product_id 
        AND pa.attribute_id = 7) AS `Length`,

        (SELECT `text` 
        FROM product_attribute pa 
        WHERE pa.product_id = p.product_id 
        AND pa.attribute_id = 5) AS `Ring Gauge`,

        (SELECT `text` 
        FROM product_attribute pa 
        WHERE pa.product_id = p.product_id 
        AND pa.attribute_id = 4) AS `Strength`,

        (SELECT `text` 
        FROM product_attribute pa 
        WHERE pa.product_id = p.product_id 
        AND pa.attribute_id = 3) AS `Wrapper`,

        CASE
        WHEN p.`status` = 1
        THEN 'active'
        ELSE 'non-active'
        END  AS `Status` ,
        md.name as                  `Manufacturer`,
        FORMAT(p.price, 2) as   `Price`,
        FORMAT(p.cost, 2) as    `Cost`,
        FORMAT(p.wholesale, 2) as   `Wholesale`,                

        CASE
        WHEN pts.`store_id` = 0
        THEN 'StogieBoys.com'
        WHEN pts.`store_id` = 1
        THEN 'CigarHeist.com'
        WHEN pts.`store_id` = 2
        THEN 'm.stogieboys.com'
        WHEN pts.`store_id` = 3
        THEN 'BestCigarStuff.com'
        WHEN pts.`store_id` = 6
        THEN 'SBCigarWholesale.com'
        WHEN pts.`store_id` = 8
        THEN 'StogieTrade.com'
        ELSE 'None'
        END  AS                         `Store`,

        CASE
        WHEN p.`is_dropshipped` = 1
        THEN 'Yes'
        ELSE 'No'
        END  AS                         `Is Dropshipped`        

        FROM
        product p,
        product_description pd,
        product_to_category ptc,
        category_description cd,
        manufacturer md,
        product_to_store pts
        WHERE 1
        AND p.product_id = pd.product_id
        AND p.product_id = ptc.product_id
        AND ptc.category_id = cd.category_id
        AND p.manufacturer_id = md.manufacturer_id
        AND p.product_id = pts.product_id
        ORDER BY pd.name        
         "; 
         $query = $this->db->query($products_sql);
         return $query->rows;   
    }
}

在大多数情况下,这工作正常。它失败的地方是 store_id 部分。CASE 只会返回第一个匹配的值,然后进入下一位。我需要它来匹配并列出产品可能出现的所有商店,就像它对类别所做的一样。

当上述方法不起作用时,我尝试将其设置为像 AS '类别' 有点像这样:

s.name as                   `Store`,

CASE
WHEN p.`is_dropshipped` = 1
THEN 'Yes'
ELSE 'No'
END  AS                         `Is Dropshipped`        

FROM
product p,
product_description pd,
product_to_category ptc,
category_description cd,
manufacturer md,
store s,
product_to_store pts
WHERE 1
AND p.product_id = pd.product_id
AND p.product_id = ptc.product_id
AND ptc.category_id = cd.category_id
AND p.manufacturer_id = md.manufacturer_id
AND p.product_id = pts.product_id
AND pts.store_id = s.store_id
ORDER BY pd.name    

但这并没有按预期工作,因为在存储表中,默认存储为 0,并且该表以多存储设置的其他存储开始。IE 1 等等,但没有列出默认值,或者 0 存储。

设计此查询以获得我希望的结果的最佳方法是什么?

4

1 回答 1

2

哦,伙计,你听说过JOIN( LEFT, RIGHT, OUTER, ...) 吗?

您的巨大查询是如何做错的一个很好的例子,这里是应该如何以正确方式完成的例子:

public function getProducts() {
    // retrieve products with basic data
    $products = $this->db->query("SELECT
    p.product_id              `Product ID`, 
    p.model                   `Model`,
    p.sku                     `SKU`,
    pd.name                   `Product Name`,
    cd.name                   `Category`,
    p.location                `Location`,
    p.quantity                `Quanity`,
    p.`status`                `Status` ,
    md.name                   `Manufacturer`,
    FORMAT(p.price, 2)        `Price`,
    FORMAT(p.cost, 2)         `Cost`,
    FORMAT(p.wholesale, 2)    `Wholesale`,                
    pts.`store_id`            `Store`,
    p.`is_dropshipped`        `Is Dropshipped`        

    FROM product p,
        LEFT JOIN product_description pd ON pd.product_id = p.product_id AND pd.language_id = " . (int)$this->config->get('config_language_id') . "
        LEFT JOIN product_to_category ptc ON ptc.product_id = p.product_id,
        LEFT JOIN category_description cd ON cd.category_id = ptc.category_id AND cd.language_id = " . (int)$this->config->get('config_language_id') . "
        LEFT JOIN manufacturer m ON m.manufacturer_id = p.manufacturer_id
        LEFT JOIN product_to_store pts ON pts.product_id = p.product_id

    ORDER BY pd.name")->rows;

    foreach($products as $key => $product) {
        $products[$key]['Box Count']  = $this->getProductAttributeValue($product['product_id'], 6);
        $products[$key]['Length']     = $this->getProductAttributeValue($product['product_id'], 7);
        $products[$key]['Ring Gauge'] = $this->getProductAttributeValue($product['product_id'], 5);
        $products[$key]['Strength']   = $this->getProductAttributeValue($product['product_id'], 4);
        $products[$key]['Wrapper']    = $this->getProductAttributeValue($product['product_id'], 3);
    }

    return $products;   
}

public function getProductAttributeValue($product_id, $attribute_id) {
    $query = $this->db->query("SELECT `text` 
    FROM product_attribute pa 
    WHERE pa.product_id = " . (int).$product_id . "
    AND pa.attribute_id = " . (int)$attribute_id);

    return $query->row['text'];
}

正如您可能提到的,我CASE WHEN从 SQL 中删除了所有这些,因为这些逻辑解释statusstore_id应该在您的模板或控制器中完成。SQL 查询(和模型)应该只检索和存储数据,并且您应该使您的 SQL 查询尽可能简单......还提到使用LEFT JOINs......

对于0商店(在您的产品中将是NULL没有价值),当然要显示正确的商店名称。它不是0(零)而是NULL,而是一个简单的检查:

if($product['store_id']) {
    // we have store_id
} else {
    // store_id is not set (NULL), display as the main store
}

在这里就够了……

于 2013-11-14T09:42:01.223 回答