php - Magento: obtener la colección de productos ordenados por precio mínimo
mysql sorting (1)
Me temo que no estoy lo suficientemente familiarizado con Magento para ayudar directamente con su código, pero, en términos más generales, esta es una pregunta común cuando se trata de SQL SELECT
consultas.
AGRUPAR POR
En primer lugar, una aclaración importante: al usar GROUP BY
, cualquier campo en la parte SELECT
de la consulta no incluida en la cláusula GROUP BY
puede no ser legal. El resultado depende de la versión de su servidor y / o del modo ONLY_FULL_GROUP_BY
SQL.
Más importante aún, suponiendo que su servidor / configuración lo admite, seleccionar campos no incluidos en la cláusula GROUP BY
significa que obtiene un valor de una fila arbitraria en el grupo, no en la primera fila . Desde la página Manejo de MySQL de GROUP BY en la documentación de MySQL:
En este caso, el servidor puede elegir libremente cualquier valor de cada grupo, de modo que, a menos que sean iguales, los valores elegidos son indeterminados, lo que probablemente no sea lo que usted desea.
Seleccionar filas específicas dentro de grupos
Una forma de lograr el comportamiento que busca que siempre me ha funcionado es usar contadores y subconsultas para ordenar y filtrar sus subgrupos. Esto le proporciona un mayor nivel de control que un GROUP BY
(aunque realiza algunos sacrificios de rendimiento):
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;
Para comprender más claramente cómo funciona esto, ejecute la consulta sin la cláusula HAVING
. Obtienes un resultado como este:
+------+------------+-------------+---------------+---------------+
| 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 |
+------+------------+-------------+---------------+---------------+
La columna b
muestra el valor de la variable @num
, que se incrementa para cada fila en un grupo de productos de nombre idéntico, y se restablece cada vez que el nombre del producto en la fila actual no es igual al nombre del último. Agregar la cláusula HAVING b=1
significa que solo obtenemos el producto más barato en cada grupo.
¡Un posible error al usar ORDER BY
en subconsultas!
La última vez que utilicé MySQL, la solución anterior funcionaría (y me imagino que eso sigue siendo cierto ahora). Sin embargo, este no es realmente el comportamiento estándar de SQL. Los servidores de bases de datos que se adhieren más estrictamente al estándar (como MariaDB) ignorarán una cláusula ORDER BY
contenida dentro de una subconsulta , a menos que la subconsulta también tenga una cláusula LIMIT
. Por lo tanto, si está utilizando MariaDB, debe forzar al servidor a respetar el ORDER BY
incluyendo un LIMIT
. Una técnica que he usado antes (como se describe en un comentario en el enlace anterior) es especificar un valor LIMIT
muy grande:
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;
Espero que eso ayude.
Resumen del entorno de trabajo
Estoy trabajando en un sitio web donde tenemos clientes y distribuidores. Cada distribuidor puede tener su propio precio para un producto.
Los datos de recolección de producción tienen otro registro duplicado (PRODUCTO DE CLONACIÓN) para cada producto que tiene el precio de ese vendedor. Por ejemplo, si el catálogo maestro tiene IPHONE 6S. de 5 distribuidores que operan en Iphone 6s pueden tener sus propios precios. El producto de clonación crea una nueva identificación de producto relacionada con la identificación del vendedor
Requisito
Necesito obtener la lista de productos de categoría sabia teniendo el precio más bajo del distribuidor. También necesita ordenar esa lista de acuerdo al precio más bajo.
lo intenté
Actualmente puedo enumerar todos los productos que tienen el precio más bajo según la categoría.
$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'');
Descubrí el precio de venta más bajo, precio especial, mrp de un distribuidor.
Al usar Agrupar por el cual se agrupan todos los datos por Nombre del producto, se obtiene el MÍNIMO del Precio más bajo, CLASIFICANDO según el Precio MÁS BAJO.
PROBLEMA
Como le expliqué, estoy usando GROUP BY Name para poder tener productos únicos, pero no puedo obtener la ID de PRODUCTO del vendedor asociado que tiene el precio más bajo. Necesito obtener la identificación del vendedor de tener el PRECIO MÁS BAJO
GROUP BY siempre Devuelve el primer ROW, pero la función MIN () da el precio más bajo. First ROW no tiene la identificación de producto asociada del precio más bajo .....
EDITAR - MYSQL QUERY
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`
Por favor ayuda si hay alguna manera EN MAGENTO