Magento: получение коллекции продуктов Сортировка по минимальной цене
Сводка рабочей среды
Я работаю над сайтом, на котором у нас есть клиент и дилеры. Каждый дилер может иметь собственную цену за продукт.
Данные по сбору продукции имеют другую дублирующую запись (CLONING PRODUCT) для каждого продукта, имеющего цену этого продавца. Например, если в главном каталоге есть IPHONE 6S. чем 5 дилеров, которые занимаются Iphone 6, могут иметь свои собственные цены. Продукт клонирования создает новый идентификатор продукта, связанный с идентификатором продавца
Требование
Мне нужно получить список наименований категории, имеющих самую низкую цену дилера. Также необходимо отсортировать этот список в соответствии с самой низкой ценой.
что я пробовал
В настоящее время я могу перечислить все продукты, имеющие самую низкую цену в соответствии с категорией.
$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');
Я нахожу самую низкую из продажной цены, специальной цены, mrp дилера.
Использование группы. По каким группам все данные по названию продукта получите МИНИМУМ самой низкой цены, СОРТИНГ, согласно НИЗКОЙ ЦЕНЕ.
ПРОБЛЕМА
Как я объяснил, я использую GROUP BY Name, чтобы иметь уникальные продукты, но я не могу получить идентификатор PRODUCT, у которого самая низкая цена. Мне нужно получить идентификатор продавца с самой низкой ценой
GROUP BY всегда Возвращает первую ROW, но функция MIN() дает самую низкую цену. Первая ROW не имеет связанного идентификатора продукта самой низкой цены.....
EDIT - QUICY 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`
Помогите, если есть какой-либо способ IN MAGENTO
Ответы
Ответ 1
Я боюсь, что я недостаточно хорошо знаком с Magento, чтобы напрямую помочь с вашим кодом, но, в общем, это общий вопрос, когда дело доходит до запросов SQL SELECT
.
GROUP BY
Во-первых, важное разъяснение: при использовании GROUP BY
любые поля в SELECT
части запроса, не включенные в предложение GROUP BY
, могут быть не законными. Результат зависит от версии вашего сервера и/или режима ONLY_FULL_GROUP_BY
SQL.
Что еще более важно, если ваш сервер/конфигурация поддерживает его, выбор полей, не включенных в предложение GROUP BY
, означает, что вы получаете значение из произвольной строки в группе, не первая строка. Из обработки MySQL страницы GROUP BY в документации по MySQL:
В этом случае сервер может выбирать любое значение из каждой группы, поэтому, если они не совпадают, выбранные значения являются неопределенными, что, вероятно, не является тем, что вы хотите.
Выбор определенных строк внутри групп
Один из способов достижения поведения, который вы ищете, всегда хорошо работал у меня - это использовать счетчики и подзапросы для упорядочения и фильтрации ваших подгрупп. Это дает вам более высокий уровень контроля, чем GROUP BY
(хотя вы жертвуете некоторыми жертвами производительности):
SELECT @num := IF([email protected]_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;
Чтобы лучше понять, как это работает, запустите запрос без предложения HAVING
. Вы получите такой результат:
+------+------------+-------------+---------------+---------------+
| 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 |
+------+------------+-------------+---------------+---------------+
В столбце b
указано значение переменной @num
, которая увеличивается для каждой строки в группе продуктов с одинаковым именем и reset каждый раз, когда имя продукта в текущей строке не равно значению имя последнего. Добавление предложения HAVING b=1
означает, что мы получаем только самый дешевый продукт в каждой группе.
Потенциальная информация при использовании ORDER BY
в подзапросах!
Когда я в последний раз использовал MySQL, это решение могло бы работать (и я думаю, что это все еще верно сейчас). Однако это не стандартное поведение SQL. Серверы баз данных, которые более строго придерживаются стандарта (например, MariaDB) будут игнорировать предложение ORDER BY
, содержащееся в подзапросе, если только в подзапросе нет LIMIT
. Поэтому, если вы используете MariaDB, вам нужно заставить сервер соблюдать ORDER BY
, включив LIMIT
. Техника, которую я использовал ранее (как описано в комментарии к предыдущей ссылке), заключается в том, чтобы указать очень большое значение LIMIT
:
SELECT @num := IF([email protected]_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;
Я надеюсь, что это поможет.