简体   繁体   English

Magento:获取产品系列按最低价格排序

[英]Magento : Getting Product Collection Sorted by minimum price

Summary of Work Environment 工作环境综述

I am working on a website where we have customer and dealers both. 我正在一个我们有客户和经销商的网站上工作。 Each Dealer can have their own price for a product. 每个经销商都可以为产品定价。

Production collection data is having another duplicate record (CLONING PRODUCT) for each product having price of that seller. 生产收集数据具有另一个具有该卖方价格的产品的重复记录(克隆产品)。 For example if master catalog have IPHONE 6S . 例如,如果主目录有IPHONE 6S。 than 5 dealers who deal in Iphone 6s can have their own prices. 超过5个交易Iphone 6s的经销商可以有自己的价格。 Cloning product creates a new product ID related to Seller ID 克隆产品会创建与卖家ID相关的新产品ID

Requirement 需求

I need to get the category wise product listing having lowest price of dealer. 我需要获得具有最低价格的经销商的类别明智的产品列表。 Also need to sort that listing according to lowest price. 还需要根据最低价格对该列表进行排序。

what I tried 我尝试了什么

Currently I can list out all the products having lowest price according to category. 目前我可以根据类别列出所有价格最低的产品。

$productCollection = Mage::getResourceModel('catalog/product_collection')
                    ->addAttributeToSelect('sellingprice')
                    ->setStoreId($storeId)
                    ->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
                    ->addAttributeToFilter('category_id', array('in' => $_POST['category_id']))
                    ->addAttributeToFilter('status', array('eq' => 1))
                    ->addAttributeToFilter('dis_continue', array('eq' => 0));



$productCollection->addAttributeToFilter('seller_id', array('in' => $seller_list));

$productCollection->addExpressionAttributeToSelect(
                    'lowest_price', 'IF(({{special_from_date}}<=now() AND {{special_to_date}}>=now() OR {{special_from_date}} IS NULL AND {{special_price}}>0),{{special_price}},IF({{sellingprice}}>0,{{sellingprice}},{{price}}))', array('special_from_date', 'special_to_date', 'special_price', 'sellingprice', 'price'));


$productCollection->getSelect()->columns('MIN(IF((IF(at_special_from_date.value_id > 0, at_special_from_date.value, at_special_from_date_default.value)<=now() AND IF(at_special_to_date.value_id > 0, at_special_to_date.value, at_special_to_date_default.value)>=now() OR IF(at_special_from_date.value_id > 0, at_special_from_date.value, at_special_from_date_default.value) IS NULL AND at_special_price.value>0),at_special_price.value,IF(at_sellingprice.value>0,at_sellingprice.value,at_price.value))) as l_price')->group('product_name');

I find out lowest of selling price , special price , mrp of a dealer. 我发现最低的销售价格,特价,经销商的mrp。

Using Group By which groups all the data by Product Name , get MINIMUM of Lowest Price , SORTING that according to LOWEST Price. 使用Group按产品名称对所有数据进行分组,获得最低价格的MINIMUM,按照LOWEST Price分类。

PROBLEM 问题

As I explained that I am Using GROUP BY Name so that I can have unique products but I am not able to get the PRODUCT ID of associated seller who is having lowest price. 正如我解释的那样,我正在使用GROUP BY Name,这样我才能拥有独特的产品,但我无法获得价格最低的相关卖家的PRODUCT ID。 I need to get the Seller ID Of having LOWEST PRICE 我需要获得最低价格的卖家ID

GROUP BY always Returns the first ROW , but MIN() function gives the lowest of price. GROUP BY总是返回第一个ROW,但MIN()函数给出最低的价格。 First ROW do not have the associated PRODUCT ID of lowest price..... First ROW没有相关的最低价格的PRODUCT ID .....

EDIT - MYSQL QUERY 编辑 - MYSQL查询

SELECT `e`.*,
`at_category_id`.`category_id`,
IF(
  at_status.value_id > 0,
  at_status.value,
  at_status_default.value
) AS `status`,
`at_dis_continue`.`value` AS `dis_continue`,
`at_seller_id`.`value` AS `seller_id`,
`at_popular_product`.`value` AS `popular_product`,
IF(
  at_special_from_date.value_id > 0,
  at_special_from_date.value,
  at_special_from_date_default.value
) AS `special_from_date`,
IF(
  at_special_to_date.value_id > 0,
  at_special_to_date.value,
  at_special_to_date_default.value
) AS `special_to_date`,
`at_special_price`.`value` AS `special_price`,
`at_sellingprice`.`value` AS `sellingprice`,
`at_price`.`value` AS `price`,
IF(
  (
    IF(
      at_special_from_date.value_id > 0,
      at_special_from_date.value,
      at_special_from_date_default.value
    ) <= NOW() AND IF(
      at_special_to_date.value_id > 0,
      at_special_to_date.value,
      at_special_to_date_default.value
    ) >= NOW() OR IF(
      at_special_from_date.value_id > 0,
      at_special_from_date.value,
      at_special_from_date_default.value
    ) IS NULL AND at_special_price.value > 0
  ),
  at_special_price.value,
  IF(
    at_sellingprice.value > 0,
    at_sellingprice.value,
    at_price.value
  )
) AS `lowest_price`,
`at_name`.`value` AS `name`,
`at_name`.`value` AS `product_name`,
MIN(
  IF(
    (
      IF(
        at_special_from_date.value_id > 0,
        at_special_from_date.value,
        at_special_from_date_default.value
      ) <= NOW() AND IF(
        at_special_to_date.value_id > 0,
        at_special_to_date.value,
        at_special_to_date_default.value
      ) >= NOW() OR IF(
        at_special_from_date.value_id > 0,
        at_special_from_date.value,
        at_special_from_date_default.value
      ) IS NULL AND at_special_price.value > 0
    ),
    at_special_price.value,
    IF(
      at_sellingprice.value > 0,
      at_sellingprice.value,
      at_price.value
    )
  )
) AS `l_price`
FROM
  `catalog_product_entity` AS `e`
LEFT JOIN
  `catalog_category_product` AS `at_category_id` ON(
    at_category_id.`product_id` = e.entity_id
  )
INNER JOIN
  `catalog_product_entity_int` AS `at_status_default` ON(
    `at_status_default`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_status_default`.`attribute_id` = '96'
  ) AND `at_status_default`.`store_id` = 0
LEFT JOIN
  `catalog_product_entity_int` AS `at_status` ON(
    `at_status`.`entity_id` = `e`.`entity_id`
  ) AND(`at_status`.`attribute_id` = '96') AND(`at_status`.`store_id` = 1)
INNER JOIN
  `catalog_product_entity_int` AS `at_dis_continue` ON(
    `at_dis_continue`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_dis_continue`.`attribute_id` = '261'
  ) AND(`at_dis_continue`.`store_id` = 0)
INNER JOIN
  `catalog_product_entity_varchar` AS `at_seller_id` ON(
    `at_seller_id`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_seller_id`.`attribute_id` = '134'
  ) AND(`at_seller_id`.`store_id` = 0)
INNER JOIN
  `catalog_product_entity_varchar` AS `at_popular_product` ON(
    `at_popular_product`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_popular_product`.`attribute_id` = '1078'
  ) AND(
    `at_popular_product`.`store_id` = 0
  )
LEFT JOIN
  `catalog_product_entity_datetime` AS `at_special_from_date_default` ON(
    `at_special_from_date_default`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_special_from_date_default`.`attribute_id` = '77'
  ) AND `at_special_from_date_default`.`store_id` = 0
LEFT JOIN
  `catalog_product_entity_datetime` AS `at_special_from_date` ON(
    `at_special_from_date`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_special_from_date`.`attribute_id` = '77'
  ) AND(
    `at_special_from_date`.`store_id` = 1
  )
LEFT JOIN
  `catalog_product_entity_datetime` AS `at_special_to_date_default` ON(
    `at_special_to_date_default`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_special_to_date_default`.`attribute_id` = '78'
  ) AND `at_special_to_date_default`.`store_id` = 0
LEFT JOIN
  `catalog_product_entity_datetime` AS `at_special_to_date` ON(
    `at_special_to_date`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_special_to_date`.`attribute_id` = '78'
  ) AND(
    `at_special_to_date`.`store_id` = 1
  )
LEFT JOIN
  `catalog_product_entity_decimal` AS `at_special_price` ON(
    `at_special_price`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_special_price`.`attribute_id` = '76'
  ) AND(`at_special_price`.`store_id` = 0)
LEFT JOIN
  `catalog_product_entity_decimal` AS `at_sellingprice` ON(
    `at_sellingprice`.`entity_id` = `e`.`entity_id`
  ) AND(
    `at_sellingprice`.`attribute_id` = '143'
  ) AND(`at_sellingprice`.`store_id` = 0)
LEFT JOIN
  `catalog_product_entity_decimal` AS `at_price` ON(
    `at_price`.`entity_id` = `e`.`entity_id`
  ) AND(`at_price`.`attribute_id` = '75') AND(`at_price`.`store_id` = 0)
LEFT JOIN
  `catalog_product_entity_varchar` AS `at_name` ON(
    `at_name`.`entity_id` = `e`.`entity_id`
  ) AND(`at_name`.`attribute_id` = '71') AND(`at_name`.`store_id` = 0)
WHERE
  (
    at_category_id.category_id IN('119')
  ) AND(
    IF(
      at_status.value_id > 0,
      at_status.value,
      at_status_default.value
    ) = 1
  ) AND(at_dis_continue.value = 0) AND(at_seller_id.value IN('1065')) AND(
    at_popular_product.value IN('Yes',
    'No')
  )
GROUP BY
  `product_name`

Please help if there is any way IN MAGENTO 如果IN MAGENTO有任何办法,请帮忙

I'm afraid I'm not familiar enough with Magento itself to help directly with your code, but, more generally speaking, this is a common question when it comes to SQL SELECT queries. 我担心我不熟悉Magento本身直接帮助你的代码,但更一般地说,这是一个常见的问题,当谈到SQL SELECT查询。

GROUP BY 通过...分组

Firstly, an important clarification: When using GROUP BY , any fields in the SELECT part of the query not included in the GROUP BY clause itself may not be legal. 首先,一个重要的澄清:当使用GROUP BY ,查询的SELECT部分中未包含在GROUP BY子句中的任何字段本身可能都不合法。 The outcome depends on your server version and/or the ONLY_FULL_GROUP_BY SQL mode. 结果取决于您的服务器版本和/或ONLY_FULL_GROUP_BY SQL模式。

More importantly, assuming your server/configuration supports it, selecting fields not included in the GROUP BY clause means you get a value from an arbitrary row in the group, not the first row . 更重要的是,假设您的服务器/配置支持它,选择GROUP BY子句中未包含的字段意味着您从组中的任意行获取值, 而不是第一行 From the MySQL Handling of GROUP BY page in the MySQL documentation: 从MySQL文档中的SMB处理GROUP BY页面

In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want. 在这种情况下,服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的,这可能不是您想要的。

Selecting specific rows within groups 选择组内的特定行

One way of achieving the behaviour you're looking for that has always worked well for me is by using counters and sub-queries to order and filter your sub-groups. 实现您正在寻找的行为的一种方法一直适用于我,方法是使用计数器和子查询来排序和过滤您的子组。 This gives you a greater level of control than a GROUP BY (although you do make some performance sacrifices): 这为您提供了比GROUP BY更高级别的控制(尽管您确实做出了一些性能牺牲):

SELECT @num := IF(products_name=@last_products_name, @num + 1, 1) b, (@last_products_name := products_name) AS last_pname, t1.*
FROM (
    SELECT p.products_id, p.products_name, p.selling_price
    FROM products p
    WHERE p.category_id = 123
    ORDER BY p.products_name,
    p.selling_price ASC
) t1, (SELECT @num := 0, @last_products_name := 0) d
HAVING b=1;

To understand more clearly how this works, run the query without the HAVING clause. 要更清楚地了解其工作原理,请运行不带HAVING子句的查询。 You get a result like this: 你得到这样的结果:

+------+------------+-------------+---------------+---------------+
| b    | last_pname | products_id | products_name | selling_price |
+------+------------+-------------+---------------+---------------+
|    1 | Bar        |           8 | Bar           |          5.00 |
|    2 | Bar        |           2 | Bar           |         12.00 |
|    3 | Bar        |           4 | Bar           |         14.00 |
|    1 | Fizz       |           3 | Fizz          |         30.00 |
|    2 | Fizz       |           5 | Fizz          |         70.00 |
|    3 | Fizz       |           7 | Fizz          |        100.00 |
|    1 | Foo        |           1 | Foo           |         10.00 |
|    2 | Foo        |           6 | Foo           |         18.00 |
+------+------------+-------------+---------------+---------------+

The b column shows the value of the @num variable, which is incremented for each row in a group of identically named products, and reset each time the product name in the current row is not equal to the name of the last one. b列显示@num变量的值,该变量对于一组具有相同名称的产品中的每一行递增,并在每次当前行中的产品名称不等于最后一行的名称时重置。 Adding the HAVING b=1 clause means we only get the cheapest product in each group. 添加HAVING b=1条款意味着我们只能获得每组中最便宜的产品。

A potential gotcha when using ORDER BY in sub-queries! 在子查询中使用ORDER BY时可能遇到的问题!

When I last used MySQL, the above solution would work (and I imagine that is still true now). 当我上次使用MySQL时,上述解决方案将起作用(我想现在仍然如此)。 However, this is not actually standard SQL behaviour. 但是,这实际上不是标准的SQL行为。 Database servers which adhere more strictly to the standard (such as MariaDB) will ignore an ORDER BY clause contained within a sub-query , unless the sub-query also features a LIMIT clause. 更严格遵守标准的数据库服务器(如MariaDB) 将忽略子查询中包含的ORDER BY子句 ,除非子查询还具有LIMIT子句。 Therefore, if you are using MariaDB, you need to force the server to honour the ORDER BY by including a LIMIT . 因此,如果您使用的是MariaDB,则需要通过包含LIMIT强制服务器遵守ORDER BY A technique I have used before (as described in a comment on the previous link) is to specify a very large LIMIT value: 我之前使用过的技术(如前一个链接的注释中所述)是指定一个非常大的LIMIT值:

SELECT @num := IF(products_name=@last_products_name, @num + 1, 1) b, (@last_products_name := products_name) AS last_pname, t1.*
FROM (
    SELECT p.products_id, p.products_name, p.selling_price
    FROM products p
    WHERE p.category_id = 123
    ORDER BY p.products_name,
    p.selling_price ASC
    LIMIT 18446744073709551615 -- LIMIT clause forces sub-query ORDER BY
) t1, (SELECT @num := 0, @last_products_name := 0) d
HAVING b=1;

I hope that helps. 我希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM