Problema al usar "tener" en la colección Magento

20

Estoy tratando de construir una colección personalizada para una cuadrícula en el módulo de administración de Magento. He creado un nuevo método de colección llamado "addAttributeHaving" que solo hace lo siguiente:

public function addAttributeHaving($value)
{
    $this->getSelect()->having($value);
    return $this;
}

Ver código de colección:

$collection->addFieldToSelect(
    array(
        'entity_id',
        'created_at',
        'increment_id',
        'customer_email',
        'customer_firstname',
        'customer_lastname',
        'grand_total',
        'status'
    )
);

$collection->getSelect()->joinLeft(array('sfop' => 'sales_flat_order_payment'), 'main_table.entity_id = sfop.parent_id', 'sfop.amount_authorized');
$collection->getSelect()->columns('sum(sfop.amount_authorized) AS AUTHD');
$collection->getSelect()->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
$collection->addFieldToFilter('main_table.state', array('in' => array('new','payment_review')));
$collection->addFieldToFilter('main_table.sd_order_type', array('neq' => 7));
$collection->addFieldToFilter('sfop.method', array('neq' => 'giftcard'));
$collection->addFieldToFilter('main_table.created_at', array('gt' => $this->getFilterDate()));
$collection->getSelect()->group(array('main_table.entity_id'));
$collection->addAttributeHaving('DIF_AU <> 0');
$collection->load(true,true);

$this->setCollection($collection);

Esto produce el siguiente SQL que se ejecuta perfectamente bien y produce los resultados esperados cuando se ejecuta fuera de Magento.

[METHOD=Varien_Data_Collection_Db->printLogQuery] SELECT `main_table`.`entity_id`, `main_table`.`entity_id`, `main_table`.`created_at`, `main_table`.`increment_id`, `main_table`.`customer_email`, `main_table`.`customer_firstname`, `main_table`.`customer_lastname`, `main_table`.`grand_total`, `main_table`.`status`, `sfop`.`amount_authorized`, sum(sfop.amount_authorized) AS `AUTHD`, grand_total - sum(sfop.amount_authorized) AS `DIF_AU` FROM `sales_flat_order` AS `main_table` LEFT JOIN `sales_flat_order_payment` AS `sfop` ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('new', 'payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY `main_table`.`entity_id` HAVING (DIF_AU <> 0)

Sin embargo, cuando intento cargar la cuadrícula dentro de Magento me sale el siguiente error:

SQLSTATE [42S22]: columna no encontrada: 1054 Columna desconocida 'DIF_AU' en 'tener cláusula'

Además, si elimino la cláusula have (que rompe mis resultados), puedo usar la columna DIF_AU para un origen de datos en la cuadrícula.

Anthony Leach Jr
fuente
1
ACTUALIZACIÓN: pude rastrear el problema hasta el método getSelectCountSql () principal. Aquí es donde está ocurriendo el problema cuando se intenta obtener el recuento de la colección.
Anthony Leach Jr
1
Publica una respuesta! ¿De qué sd_order_typeviene eso ?
Benmarks
1
Material de tipo de orden personalizado de alto secreto que se ha agregado a tablas planas. Todavía estoy trabajando en la respuesta.
Anthony Leach Jr
1
"Los usuarios con menos de 10 reputación no pueden responder su propia pregunta durante 8 horas después de haberla preguntado. Puede responder en 7 horas. Hasta entonces, utilice los comentarios o edite su pregunta". (solución para venir en 7 horas).
Anthony Leach Jr
1
Alguien le da a este hombre un
voto positivo

Respuestas:

12

Realmente voy a responder mi propia pregunta aquí. Lo sé, de mal gusto, pero me topé con la respuesta al mirar mucho más de cerca el rastro real de la pila. La colección se está cargando bien, sin embargo, la falla llega un poco más tarde en la ejecución cuando intentamos obtener el recuento de la colección en Varien_Data_Collection_Db :: getSelectCountSql () . El SQL que se produce a partir de esto es:

SELECT COUNT(*) FROM sales_flat_order AS main_table LEFT JOIN sales_flat_order_payment AS sfop ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY main_table.entity_id HAVING (DIF_AU <> 0)

Notará que la declaración HAVING está adjunta, pero ya no tenemos una definición para la columna DIF_AU. Parece que tendré que extender un getSelectCountSql () personalizado en mi clase de colección para obtener el recuento de registros correcto.

He creado un getSelectCountSql () extendido en la clase de colección personalizada que se agrega de nuevo en la columna faltante requerida para la instrucción have.


public function getSelectCountSql()
  {
    $countSelect = parent::getSelectCountSql();
    $countSelect->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
    $countSelect->reset(Zend_Db_Select::GROUP);
    return $countSelect;
  }
Anthony Leach Jr
fuente
1
No es pegajoso en absoluto ... si primero descubres la solución, se recomienda. Otros potencialmente lo encontrarán útil en el futuro. +1 :)
davidalger
¡Debería presentar un informe de error! magentocommerce.com/bug-tracking
puntos de referencia
Este es un problema que también he visto, y bien hecho para encontrar una respuesta. Sin embargo, no creo que su solución sea correcta, ya que está usando group by, su SelectCountSql necesita devolver el número de grupos. Por lo tanto, necesita un recuento (fetchAll ()) o reescribir su consulta usando en count(distinct main_table.entity_id)lugar decount(*)
Benubird
Creo que es muy probable que tengas razón. Este proyecto ha estado en segundo plano desde esta publicación, y justo ahora volviendo a él. En una demostración la semana pasada, noté que se contaba un recuento de registros incorrecto en la cuadrícula. Informaré de mis hallazgos una vez que lo haya resuelto.
Anthony Leach Jr
@AnthonyLeachJr alguna noticia sobre sus hallazgos?
Simon
0

En primer lugar, $countSelect->reset(Zend_Db_Select::HAVING);significa que se restablecerá HAVINGdesde su colección. Eso significa que eliminará la cláusula have. Y no es lo que quieres. Es posible que desee agregarlo a la colección ( app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php->_getSelectCountSql()aquí).

Pero el principal culpable es el getSize()método que existe en el lib/Varien/Data/Collection/Db.phparchivo.

Probé la solución anterior mencionada por @Anthony pero eso no funcionó.

Ahora hice lo siguiente.

public function getSize()
{
    if (is_null($this->_totalRecords)) {
        //$sql = $this->getSelectCountSql();
        $sql = $this->getSelect();
        $this->_totalRecords = count($this->getConnection()->fetchAll($sql, $this->_bindParams));
    }
    return intval($this->_totalRecords);
}

Comprueba que ni siquiera estoy usando el getSelectCountSql(). Solo estoy leyendo toda la CONSULTA SQL y obteniendo todos los datos y devuelvo el recuento . Eso es todo.

Kingshuk Deb
fuente
0

Solucioné este problema aquí: app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php: 943 agregue esto: $ select-> reset (Zend_Db_Select :: HAVING);

Simplemente copie app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php a app / code / local / Mage / Catalog / Model / Resource / Product / Collection.php

Mi código ahora se ve así:

/**
 * Build clear select
 *
 * @param Varien_Db_Select $select
 * @return Varien_Db_Select
 */
protected function _buildClearSelect($select = null)
{
    if (is_null($select)) {
        $select = clone $this->getSelect();
    }
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);
    $select->reset(Zend_Db_Select::COLUMNS);
    $select->reset(Zend_Db_Select::HAVING);
Andrii K
fuente
0

Esta solución funcionará si su selección tiene nombres de columnas únicos porque cualquier columna en la lista de selección de subconsulta debe tener nombres únicos

Subconsulta: la subconsulta de tabla permite nombres de columna duplicados

public function getSelectCountSql()
{
    $this->_renderFilters();
    $select = clone $this->getSelect();
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);        

    $countSelect = clone $this->getSelect();
    $countSelect->reset();
    $countSelect->from(array('a' => $select), 'COUNT(*)');
    return $countSelect;
}

PD: Esta respuesta es para colecciones generales de magento. no relacionado solo con la colección de productos.

Minesh Patel
fuente
0

Esto esta funcionando

función pública getSize () {if (is_null ($ this -> _ totalRecords)) {// $ sql = $ this-> getSelectCountSql (); $ sql = $ this-> getSelect (); $ this -> _ totalRecords = count ($ this-> getConnection () -> fetchAll ($ sql, $ this -> _ bindParams)); } return intval ($ this -> _ totalRecords); }

jignesh patel
fuente