Problema usando "having" na coleção Magento

20

Estou tentando criar uma coleção personalizada para uma grade no módulo de administração do Magento. Eu criei um novo método de coleção chamado "addAttributeHaving", que faz o seguinte:

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

Veja o código da coleção:

$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);

Isso produz o seguinte SQL, que executa perfeitamente bem e produz os resultados esperados quando executado fora do 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)

No entanto, quando tento carregar a grade dentro do Magento, recebo o seguinte erro:

SQLSTATE [42S22]: Coluna não encontrada: 1054 Coluna desconhecida 'DIF_AU' na 'cláusula having'

Além disso, se eu remover a cláusula having (que quebra meus resultados), posso usar a coluna DIF_AU para uma fonte de dados na Grade.

Anthony Leach Jr
fonte
11
UPDATE: Consegui rastrear o problema para o método pai getSelectCountSql (). É aqui que o problema está acontecendo ao tentar obter a contagem de coleções.
Anthony Leach Jr
11
Poste uma resposta! WTH é que sd_order_typevem?
benmarks 07/07
11
Material do tipo de pedido personalizado extremamente secreto que foi adicionado a tabelas simples. Eu ainda estou trabalhando a resposta.
Anthony Leach Jr
11
"Usuários com menos de 10 reputação não podem responder suas próprias perguntas por 8 horas depois de fazer a pergunta. Você pode responder em 7 horas. Até então, use comentários ou edite sua pergunta." (solução para vir em 7 horas).
Anthony Leach Jr
11
Alguém dar a este homem uma upvote
benmarks

Respostas:

12

Na verdade, vou responder minha própria pergunta aqui. Eu sei, brega, mas me deparei com a resposta ao olhar muito mais de perto o rastreamento real da pilha. A coleção está carregando bem, no entanto, a falha ocorre um pouco mais tarde na execução, quando tentamos obter a contagem da coleção em Varien_Data_Collection_Db :: getSelectCountSql () . O SQL produzido a partir disso é:

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)

Você notará que a instrução HAVING está anexada, mas não temos mais nenhuma definição para a coluna DIF_AU. Parece que vou precisar estender um getSelectCountSql () personalizado na minha classe de coleção para obter a contagem de registros correta.

Criei um getSelectCountSql () estendido na classe de coleção personalizada que é adicionada novamente na coluna ausente necessária para a instrução having.


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
fonte
11
Nem um pouco brega ... se você descobrir a solução primeiro, é incentivado. Outros podem achar útil no futuro. +1 :)
davidalger
Você deve registrar um relatório de bug! magentocommerce.com/bug-tracking
benmarks
Essa é uma questão que eu também já vi e muito bem em encontrar uma resposta. No entanto, não acho que sua solução esteja correta - porque você está usando um grupo por, seu SelectCountSql precisa retornar o número de grupos. Então você precisa de uma contagem (fetchAll ()), ou para reescrever sua consulta usando count(distinct main_table.entity_id)em vez decount(*)
Benubird
Eu acho que você provavelmente está correto. Este projeto está em segundo plano desde esta postagem e agora está voltando a ele. Em uma demonstração na semana passada, notei uma contagem incorreta de registros sendo relatada na grade. Vou relatar minhas descobertas assim que eu as tiver resolvido.
Anthony Leach Jr
@AnthonyLeachJr alguma notícia sobre suas descobertas?
Simon
0

Antes de tudo $countSelect->reset(Zend_Db_Select::HAVING);, ele será redefinido HAVINGda sua coleção. Isso significa que ele removerá a cláusula having. E não é o que você quer. Você pode adicioná-lo à coleção ( app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php->_getSelectCountSql()aqui.)

Mas o principal culpado é o getSize()método que existe no lib/Varien/Data/Collection/Db.phparquivo.

Tentei a solução acima mencionada por Anthony, mas isso não funcionou.

Agora eu fiz o abaixo.

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);
}

Verifique se eu não estou nem usando o getSelectCountSql(). Estou apenas lendo todo o SQL QUERY e buscando todos os dados e retornando a contagem . Isso é tudo.

Kingshuk Deb
fonte
0

Corrigi esse problema aqui: app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php: 943 adicione isso: $ select-> reset (Zend_Db_Select :: HAVING);

Basta copiar app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php para app / code / local / Mage / Catalog / Model / Resource / Product / Collection.php

Meu código está agora assim:

/**
 * 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
fonte
0

Esta solução funcionará se a sua seleção tiver nomes de colunas exclusivos, porque qualquer coluna na lista de seleção de subconsulta deve ter nomes exclusivos

Subconsulta: a subconsulta da tabela permite nomes de colunas 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;
}

PS: Esta resposta é para coleções gerais de magento. não está relacionado apenas à coleção de produtos.

Minesh Patel
fonte
0

Isso está funcionando

função 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
fonte