Problem z użyciem „posiadania” w kolekcji Magento

20

Próbuję zbudować niestandardową kolekcję dla siatki w module administracyjnym Magento. Utworzyłem nową metodę kolekcji o nazwie „addAttributeHaving”, która wykonuje następujące czynności:

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

Zobacz kod kolekcji:

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

Powoduje to wygenerowanie następującego kodu SQL, który działa idealnie dobrze i daje oczekiwane wyniki, gdy jest uruchamiany poza 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)

Jednak gdy próbuję załadować siatkę do Magento, pojawia się następujący błąd:

SQLSTATE [42S22]: Nie znaleziono kolumny: 1054 Nieznana kolumna „DIF_AU” w „z klauzulą”

Dodatkowo, jeśli usunę klauzulę have (która psuje moje wyniki), będę mógł użyć kolumny DIF_AU jako źródła danych w siatce.

Anthony Leach Jr
źródło
1
AKTUALIZACJA: Udało mi się wyśledzić problem do nadrzędnej metody getSelectCountSql (). Właśnie w tym momencie występuje problem, gdy próbujesz uzyskać liczbę kolekcji.
Anthony Leach Jr
1
Opublikuj odpowiedź! WTH czy to sd_order_typepochodzi?
zyskuje
1
Ściśle tajne niestandardowe typy zamówień dodane do płaskich stolików. Nadal pracuję nad odpowiedzią.
Anthony Leach Jr
1
„Użytkownicy o reputacji mniejszej niż 10 nie mogą odpowiedzieć na swoje pytanie przez 8 godzin po zadaniu. Możesz odpowiedzieć w ciągu 7 godzin. Do tego czasu użyj komentarzy lub edytuj swoje pytanie”. (rozwiązanie pojawi się za 7 godzin).
Anthony Leach Jr
1
Ktoś podaruje temu mężczyźnie opinię
zyskuje

Odpowiedzi:

12

Odpowiem na własne pytanie tutaj. Wiem, tandetny, ale natknąłem się na odpowiedź, gdy przyjrzałem się bliżej faktycznemu śladowi stosu. Kolekcja ładuje się dobrze, jednak błąd pojawia się nieco później, gdy próbujemy uzyskać liczbę kolekcji w Varien_Data_Collection_Db :: getSelectCountSql () . Wytworzony z tego kod SQL to:

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)

Zauważysz, że instrukcja HAVING jest załączona, ale nie mamy już definicji kolumny DIF_AU. Wygląda na to, że będę musiał rozszerzyć niestandardową metodę getSelectCountSql () w mojej klasie kolekcji, aby uzyskać odpowiednią liczbę rekordów.

Utworzyłem rozszerzoną metodę getSelectCountSql () w niestandardowej klasie kolekcji, która dodaje z powrotem w brakującej kolumnie wymaganej dla instrukcji 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
źródło
1
W ogóle nie jest tandetny ... jeśli najpierw wymyślisz rozwiązanie, jest to zalecane. Inni potencjalnie uznają to za pomocne na drodze. +1 :)
davidalger
Powinieneś złożyć raport o błędzie! magentocommerce.com/bug-tracking
benmarks
Jest to problem, który również widziałem i dobrze zrobiłem po znalezieniu odpowiedzi. Nie sądzę jednak, aby twoje rozwiązanie było poprawne - ponieważ używasz group by, Twój SelectCountSql musi zwracać liczbę grup. Potrzebujesz więc licznika (fetchAll ()) lub przepisania zapytania, używając count(distinct main_table.entity_id)zamiastcount(*)
Benubird
Myślę, że prawdopodobnie masz rację. Ten projekt był na drugim planie od czasu tego postu i właśnie do niego wracam. W zeszłotygodniowej wersji demo zauważyłem, że w tabeli zgłoszono niepoprawną liczbę rekordów. Prześlę sprawozdanie z moich ustaleń po ich rozwiązaniu.
Anthony Leach Jr
@AnthonyLeachJr jakieś wiadomości na temat twoich ustaleń?
Simon
0

Przede wszystkim $countSelect->reset(Zend_Db_Select::HAVING);oznacza, że ​​zresetuje się HAVINGz twojej kolekcji. Oznacza to, że usunie klauzulę posiadania. I to nie jest to, czego chcesz. Możesz dodać go do kolekcji ( app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php->_getSelectCountSql()tutaj.)

Ale głównym winowajcą jest getSize()metoda, która istnieje w lib/Varien/Data/Collection/Db.phppliku.

Wypróbowałem powyższe rozwiązanie wymienione przez @Anthony, ale to nie zadziałało.

Teraz zrobiłem poniżej.

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

Sprawdź, że nawet nie używam getSelectCountSql(). Właśnie czytam całe zapytanie SQL i pobieram wszystkie dane i zwracam ich liczbę . To wszystko.

Kingshuk Deb
źródło
0

Naprawiłem ten problem tutaj: app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php: 943 dodaj to: $ select-> reset (Zend_Db_Select :: HAVING);

Wystarczy skopiować aplikację / code / core / Mage / Catalog / Model / Resource / Product / Collection.php do app / code / local / Mage / Catalog / Model / Resource / Product / Collection.php

Mój kod wygląda teraz tak:

/**
 * 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
źródło
0

To rozwiązanie będzie działać, jeśli Twój wybór ma unikalne nazwy kolumn, ponieważ wszystkie kolumny na liście wyboru podkwerend muszą mieć unikalne nazwy

Podzapytanie: podzapytanie tabeli umożliwia zduplikowanie nazw kolumn

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: Ta odpowiedź dotyczy ogólnych kolekcji Magento. niezwiązane tylko z kolekcją produktów.

Minesh Patel
źródło
0

To działa

funkcja publiczna 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
źródło