I need to use having clause in Magento custom collection grid, I try to do this:
$store = Mage::app()->getStore($this->getStore());
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('sku')
->addAttributeToSelect('name')
->addAttributeToSelect('small_image')
->addAttributeToFilter('status',1);
$collection->joinTable(array('table_url' => 'thebot_url'),"table_url.product_id = entity_id",
array(
"urls" => new Zend_Db_Expr('group_concat(table_url.url)'),
"competitor_price" => new Zend_Db_Expr('group_concat(table_url.competitor_price)'),
'rdy_shipping' => 'rdy_shipping',
'competitor_shipping_price' => 'competitor_shipping_price',
'min_sell_price' => new Zend_Db_Expr('min(ROUND((table_url.competitor_price + table_url.competitor_shipping_price),2))'),
'rdy_price' => new Zend_Db_Expr('round(((IF(at_price.value_id > 0, at_price.value, at_price_default.value)) + min(table_url.rdy_shipping)),2)')
), null,'left');
if ($store->getId())
{
$collection->addStoreFilter($store);
$collection->joinAttribute('custom_name', 'catalog_product/name', 'entity_id', null, 'inner', $store->getId());
$collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner', $store->getId());
$collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner', $store->getId());
$collection->joinAttribute('price', 'catalog_product/price', 'entity_id', null, 'left', $store->getId());
$collection->joinAttribute('manufacturer', 'catalog_product/manufacturer', 'entity_id', null, 'left', $store->getId());
}
else
{
$collection->addAttributeToSelect('price');
$collection->addAttributeToSelect('status');
$collection->addAttributeToSelect('manufacturer');
$collection->addAttributeToSelect('visibility');
}
$collection->addAttributeToFilter('visibility', array("neq" => 1));
$collection->getSelect()->group("e.entity_id");
$collection->getSelect()->having("rdy_price > min_sell_price AND min_sell_price > 0");
this error shows up:
Column not found: 1054 Unknown column 'rdy_price' in 'having clause'
The sql query is:
SELECT COUNT(DISTINCT e.entity_id) FROM `catalog_product_entity` AS `e`
INNER JOIN `catalog_product_entity_int` AS `at_status` ON (`at_status`.`entity_id` = `e`.`entity_id`) AND (`at_status`.`attribute_id` = '80') AND (`at_status`.`store_id` = 0)
INNER JOIN `catalog_product_website` AS `product_website` ON product_website.product_id = e.entity_id AND product_website.website_id = '10'
INNER JOIN `catalog_product_entity_varchar` AS `at_custom_name_default` ON (`at_custom_name_default`.`entity_id` = `e`.`entity_id`) AND (`at_custom_name_default`.`attribute_id` = '56') AND `at_custom_name_default`.`store_id` = 0
INNER JOIN `catalog_product_entity_int` AS `at_visibility_default` ON (`at_visibility_default`.`entity_id` = `e`.`entity_id`) AND (`at_visibility_default`.`attribute_id` = '85') AND `at_visibility_default`.`store_id` = 0
LEFT JOIN `catalog_product_entity_int` AS `at_visibility` ON (`at_visibility`.`entity_id` = `e`.`entity_id`) AND (`at_visibility`.`attribute_id` = '85') AND (`at_visibility`.`store_id` = '16') WHERE (at_status.value = '1') AND (IF(at_visibility.value_id > 0, at_visibility.value, at_visibility_default.value) != 1) HAVING (rdy_price > min_sell_price AND min_sell_price > 0)
So why magento doesn't join the table "table_url" into this request (which is use I think to count results)?
Use this code:
$min_sell_price = 'min(ROUND((table_url.competitor_price + table_url.competitor_shipping_price),2))';
$rdy_price = 'round(((IF(at_price.value_id > 0, at_price.value, at_price_default.value)) + min(table_url.rdy_shipping)),2)';
$collection->getSelect()->having("{$rdy_price} > {$min_sell_price} AND {$min_sell_price} > 0");
First of all reason why your query fails:
There is no GROUP BY
, but there is a HAVING
in the query.
Very suspicious.
At first I thought your code should more like the following, whilst the $collection->getSelect()
part looks to be overwritten.
$collection->getSelect()->group("e.entity_id")->having("rdy_price > min_sell_price AND min_sell_price > 0");
Actually, a little more research learned that not the query you are providing is failing you, but Magento's built-in getSelectCountSql()
.
The guy on this post about problems with GROUP BY HAVING on a Magento Collection appears to have the same sort of problems.
The solution for him was extending the getSelectCountSql()
I have created an extended getSelectCountSql() in the custom collection class that adds back in the missing column required for the having statement.
public function getSelectCountSql()
{
$countSelect = parent::getSelectCountSql();
// Adding some custom features
[...]
}
We have to track the method: Varien_Db_Select::getSelectCountSql()
. Luckily for us, someone already did this for us.
Loading a collection with
HAVING
works fine, but if you are using this in grid context, Magento might callgetSelectCountSql()
on the collection to get a modified query to retrieve the number of results.I don't know why this is not included in the default implementation, but essentially it means you cannot use HAVING with calculated columns but must repeat the expression:
Original post
Maybe you should have a look at this similar topic about joinTable
Especially the following part - why I think your query isn't working:
- Table is easy, it is the magento
namespace/entity
format, which you use in your configuration, resource models and the collection. You can use an array of the format array('alias' => 'namespace/entity')
I'm affraid your table thebot_url is a custom table. So you will need to add a resource model.
This is an example how you would add this to a module
<?xml version="1.0"?>
<config>
...
<!-- The module you are using this query on -->
<global>
...
<models>
<thebot_url>
<class>Custom_TheBotUrl_Model</class>
<resourceModel>thebot_url_mysql4</resourceModel>
</thebot_url>
<thebot_url_mysql4>
<class>Custom_TheBotUrl_Model_Mysql4</class>
<entities>
<myfirsttable>
<table>thebot_url</table>
</myfirsttable>
</entities>
</thebot_mysql4>
</models>
...
</global>
...
</config>
So now you have a namespace thebot_url
and an entity myfirsttable
which will result in magento selecting <table>thebot_url</table>
All together: In the first argument ($table
) for joinTable()
would be thebot_url/myfirsttable
for this example
For more detailed information, you might want to read this article about creating a custom module with a custom table for Magento.