What is wrong with this SQL for phpBB? - mysql

Updated SQL: Environment is MySQL 5.5. The SQL is being generated through a phpBB abstraction layer but when I see the SQL it looks valid.
SELECT f.*, t.*, p.*, u.*, tt.mark_time AS topic_mark_time, ft.mark_time AS forum_mark_time
FROM (phpbb_posts p CROSS JOIN phpbb_users u CROSS JOIN phpbb_topics t) LEFT JOIN
phpbb_forums f ON (t.forum_id = f.forum_id) LEFT JOIN phpbb_topics_track tt ON
(t.topic_id = tt.topic_id AND tt.user_id = 2) LEFT JOIN phpbb_forums_track ft ON
(f.forum_id = ft.forum_id AND ft.user_id = 2) WHERE p.topic_id = t.topic_id AND
p.poster_id = u.user_id AND p.post_time > 1380495918 AND p.forum_id IN (7, 6, 5, 3, 4, 2, 1)
AND p.post_approved = 1 ORDER BY t.topic_last_post_time DESC, p.post_time LIMIT
18446744073709551615
Error is:
Unknown column 't.topic_id' in 'on clause' [1054]
All column names exist. All tables exist. All aliases exist.
Here's the associated code:
$sql_array = array(
'SELECT' => 'f.*, t.*, p.*, u.*, tt.mark_time AS topic_mark_time, ft.mark_time AS forum_mark_time',
'FROM' => array(
POSTS_TABLE => 'p',
USERS_TABLE => 'u',
TOPICS_TABLE => 't'),
'WHERE' => "$topics_posts_join_sql
AND p.poster_id = u.user_id
$date_limit_sql
$fetched_forums_str
$new_topics_sql
$remove_mine_sql
$filter_foes_sql
AND p.post_approved = 1",
'ORDER_BY' => $order_by_sql
);
$sql_array['LEFT_JOIN'] = array(
array(
'FROM' => array(FORUMS_TABLE => 'f'),
'ON' => 't.forum_id = f.forum_id'
),
array(
'FROM' => array(TOPICS_TRACK_TABLE => 'tt', FORUMS_TRACK_TABLE => 'ft'),
'ON' => "t.topic_id = tt.topic_id AND tt.user_id = $user_id"
),
array(
'FROM' => array(FORUMS_TRACK_TABLE => 'ft'),
'ON' => "f.forum_id = ft.forum_id AND ft.user_id = $user_id"
)
);
$sql = $db->sql_build_query('SELECT', $sql_array);

t.topic_id = TOPICS_TRACK_TABLE.topic_i
Is wrong. Make sure it uses the correct alias tt

Related

Convert SQL Select Query to Magento Collection

I have a complex sql select query which actually returns sales report against specified categories. I want to load data as a collection to display but I'm not able to convert the query into Magento's equivalent getCollection statement. my query is below. thanks in advance
select
sfo.increment_id as 'orderid',
sfoi.sku,
sfoi.qty_ordered as 'qty',
IFNULL(sfoi.price_incl_tax-sfoi.discount_amount, 0) as 'productprice',
sfo.shipping_amount,
cost.value as 'price',
sfo.status,
sfo.created_at,
IF(ccp1.product_id IS NULL, 'no', 'yes') as sale,
IF(ccp2.product_id IS NULL, 'no', 'yes') as home
from sales_flat_order as sfo
join sales_flat_order_item as sfoi on sfo.entity_id = sfoi.order_id
join catalog_product_entity_decimal as cost on cost.entity_id = sfoi.product_id and cost.attribute_id = 79
left join catalog_category_product as ccp1 on sfoi.product_id = ccp1.product_id and ccp1.category_id = 8
left join catalog_category_product as ccp2 on sfoi.product_id = ccp2.product_id and ccp2.category_id = 7
where sfo.created_at between '2017-01-01' and '2017-01-02'
and sfo.status in ('processing','complete')
Magento collection statement
$collection = Mage::getModel('sales/order')->getCollection();
$collection->getSelect()->join(
array('sfoi' => $collection->getTable('sales/order_item')), 'main_table.entity_id=sfoi.order_id',
array('qty' => 'sfoi.qty_ordered', 'sku')
)->join(
array('cost' => 'catalog_product_entity_decimal'), 'cost.entity_id=sfoi.product_id and cost.attribute_id=79',
array('price' => 'cost.value')
)->joinLeft(
array('ccp1' => 'catalog_category_product'),
'sfoi.product_id = ccp1.product_id and ccp1.category_id = 8', null
)->joinLeft(
array('ccp2' => 'catalog_category_product'),
'sfoi.product_id = ccp2.product_id and ccp2.category_id = 7', null
);
$collection->addFieldToSelect('increment_id', 'orderid')
->addFieldToSelect('shipping_amount')
->addFieldToSelect('status')
->addFieldToSelect('created_at')
->addExpressionFieldToSelect(
'productprice',
'IFNULL((sfoi.price_incl_tax - {{discount_amount}}), "0")',
array(
'discount_amount' => 'sfoi.discount_amount'))
->addExpressionFieldToSelect(
'sale',
'IF({{product_id}} IS NULL, "no", "yes")',
array(
'product_id' => 'cpp1.product_id'))
->addExpressionFieldToSelect(
'home',
'IF({{product_id}} IS NULL, "no", "yes")',
array(
'product_id' => 'ccp2.product_id'))
->addAttributeToFilter('sfo.created_at', array(
'from' => '2017-01-01',
'to' => '2017-01-02',
'date' => true,
))
->addFieldToFilter('status', array('in' => array('processing','complete')));
...generated sql query
SELECT `main_table`.`increment_id` AS `orderid`,
`main_table`.`shipping_amount`,
`main_table`.`status`,
`main_table`.`created_at`,
`sfoi`.`qty_ordered` AS `qty`,
`sfoi`.`sku`,
`cost`.`value` AS `price`,
Ifnull(( sfoi.price_incl_tax - sfoi.discount_amount ), "0") AS
`productprice`,
IF(cpp1.product_id IS NULL, "no", "yes") AS `sale`,
IF(ccp2.product_id IS NULL, "no", "yes") AS `home`
FROM `sales_flat_order` AS `main_table`
INNER JOIN `sales_flat_order_item` AS `sfoi`
ON main_table.entity_id = sfoi.order_id
INNER JOIN `catalog_product_entity_decimal` AS `cost`
ON cost.entity_id = sfoi.product_id
AND cost.attribute_id = 79
LEFT JOIN `catalog_category_product` AS `ccp1`
ON sfoi.product_id = ccp1.product_id
AND ccp1.category_id = 8
LEFT JOIN `catalog_category_product` AS `ccp2`
ON sfoi.product_id = ccp2.product_id
AND ccp2.category_id = 7
WHERE ( `sfo`.`created_at` >= '2017-01-01 00:00:00'
AND `sfo`.`created_at` <= '2017-01-02 00:00:00' )
AND ( `status` IN( 'processing', 'complete' ) )

Column 'available_for_order' in where clause is ambiguous

I'm strugling with this query within prestashop , i know it could be easily fixed by changing to sa.available_for_order but this way it breaks the logic of other core files ,
is there any other way around to fix this without renaming available_for_order to sa.available_for_order ,
SELECT
a.`id_product`,
b.`name` AS `name`,
`reference`,
a.`price` AS `price`,
sa.`active` AS `active`,
`newfield`,
shop.`name` AS `shopname`,
a.`id_shop_default`,
image_shop.`id_image` AS `id_image`,
cl.`name` AS `name_category`,
sa.`price`,
0 AS `price_final`,
a.`is_virtual`,
pd.`nb_downloadable`,
sav.`quantity` AS `sav_quantity`,
sa.`active`,
IF(sav.`quantity` <= 0, 1, 0) AS `badge_danger`,
sa.`available_for_order` AS `available_for_order`
FROM
`ps_product` a
LEFT JOIN
`ps_product_lang` b
ON
(
b.`id_product` = a.`id_product` AND b.`id_lang` = 1 AND b.`id_shop` = 1
)
LEFT JOIN
`ps_stock_available` sav
ON
(
sav.`id_product` = a.`id_product` AND sav.`id_product_attribute` = 0 AND sav.id_shop = 1 AND sav.id_shop_group = 0
)
JOIN
`ps_product_shop` sa
ON
(
a.`id_product` = sa.`id_product` AND sa.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_category_lang` cl
ON
(
sa.`id_category_default` = cl.`id_category` AND b.`id_lang` = cl.`id_lang` AND cl.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_shop` shop
ON
(
shop.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_image_shop` image_shop
ON
(
image_shop.`id_product` = a.`id_product` AND image_shop.`cover` = 1 AND image_shop.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_image` i
ON
(
i.`id_image` = image_shop.`id_image`
)
LEFT JOIN
`ps_product_download` pd
ON
(pd.`id_product` = a.`id_product`)
WHERE
1 AND `available_for_order` = 1
ORDER BY
a.`id_product` ASC
LIMIT 0, 50
PRESTASHOP
public function __construct()
{
parent::__construct();
$this->_select .= ',sa.`available_for_order` AS `available_for_order`, ';
$this->fields_list['sa!available_for_order'] = array(
'title' => $this->l('Available for order'),
'width' => 90,
'active' => 'available_for_order',
'filter_key' => 'sa!available_for_order',
'type' => 'bool',
'align' => 'center',
'orderby' => false
);
}
Modify your fields list to use having filter.
$this->fields_list['available_for_order'] = array(
'title' => $this->l('Available for order'),
'width' => 90,
'active' => 'available_for_order',
'filter_key' => 'available_for_order',
'havingFilter' => true,
'type' => 'bool',
'align' => 'center',
'orderby' => false
);
This will use HAVING instead of WHERE in query.
WHERE clause does not work on column aliases but HAVING does.
The column available_for_order must be in more than one of the tables. Just qualify the column name, as you do in the select:
WHERE 1 AND sa.available_for_order = 1
------------^

How to implement ON ( ... OR ...) mysql query in doctrine2 queryBuilder

I have a SQL query in MYSQL:
For example
SELECT s.* FROM vplanning.cities as c1
INNER JOIN vplanning.cities as c2
ON (c1.id = c2.area_id)
INNER JOIN vplanning.storages as s
ON (s.city_id = c2.id OR s.city_id = c1.id)
WHERE c1.id = 109;
In doctrine I can write something like this (from my work code):
$query = $em->getRepository('VplanningPageBundle:Storage')
->createQueryBuilder('s')
->innerJoin('s.city', 'c1')
->innerJoin('c1.area', 'c2')
->innerJoin('s.storagestype', 'st')
->where('c2.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('s.adress')
->getQuery();
As you can see, I show my relation in
->innerJoin('s.city', 'c1')
but I need also relation like
->innerJoin('s.city', 'c2')
with this condition:
ON (s.city_id = c2.id OR s.city_id = c1.id)
But it throws this error:
Error: 'c2' is already defined
c1 and c2 are the same entity and have a inner relation.
Try this:
$repository = $em->getRepository('VplanningPageBundle:Storage');
$qb = $repository->createQueryBuilder('storage');
//We can now use the expr()
$qb->join('storage.city', 'city', Join::WITH)
->join('city.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress');
$query = $qb->getQuery();
Try smth like this
$qb = $this->getRepository('VplanningPageBundle:City')->createQueryBuilder('c');
$qb->leftJoin('c.area', 'a')
->join('c.storage', 's', Join::ON, $qb->expr()->orX($qb->expr()->eq('c.id', 's.id'), $qb->expr()->eq('a.id', 's.id')))
->innerJoin('s.storagestype', 'st')
->where('c.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1,
))
->orderBy('s.adress')
->getQuery()
;
The solution of the problem was very difficult as for me, I have to study it :)
This is a answer for my question from some forum board:
$qb = $em->getRepository('VplanningPageBundle:Storage')->createQueryBuilder('storage');
$query = $qb->join('storage.city', 'city1', Join::WITH)
->leftJoin('city1.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->leftJoin('storage.city', 'city2', Join::WITH, $qb->expr()->eq('city2.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->andWhere($qb->expr()->orX($qb->expr()->isNotNull('city2'), $qb->expr()->isNotNull('area')))
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress')
->getQuery();

yii query with 4 table on CActiveDataProvider

hi master i've 4 tables
-pegawai
-penilaian
-universitas
-jurusan
I usually use
SELECT u.nama_univ, j.singkatan, peg.* FROM pegawai AS peg LEFT JOIN penilaian AS pen ON pen.no_test=peg.no_test LEFT JOIN universitas AS u ON u.id=peg.univ_s1 LEFT JOIN jurusan AS j ON j.id=peg.bidang_s1
how to convert this query to yii ?
i've tried this code but it's not working well
$dataProvider = new CActiveDataProvider('Pegawai', array(
'criteria' => array(
'select' => array(
'`pen`.*',
'`u`.`nama_univ` AS `nama_univ`',
'`j`.`singkatan` AS `singkatan`'
),
'join' => 'JOIN `Penilaian` AS `pen` ON `pen`.`no_test` = `t`.`no_test`',
'join' => 'JOIN `Universitas` AS `u` ON `u`.`id` = `t`.`no_test`',
'join' => 'JOIN `Jurusan` AS `j` ON `j`.`id` = `t`.`no_test`',
)
));
but only one join there's execute
Do one thing you just print the criteria object like
$dataProvider = new CActiveDataProvider('Pegawai', array(
'criteria' => array(
'select' => array(
'`pen`.*',
'`u`.`nama_univ` AS `nama_univ`',
'`j`.`singkatan` AS `singkatan`'
),
'join' => 'JOIN `Penilaian` AS `pen` ON `pen`.`no_test` = `t`.`no_test`',
'join' => 'JOIN `Universitas` AS `u` ON `u`.`id` = `t`.`no_test`',
'join' => 'JOIN `Jurusan` AS `j` ON `j`.`id` = `t`.`no_test`',
)
));
echo "<pre>";
print_r($dataProvider); //Check the object or try to post it below
exit();
You have assigned 3 values to the same index of array ('join') so only the last one is stored.
Try:
$dataProvider = new CActiveDataProvider('Pegawai', array(
'criteria' => array(
'select' => array(
'`pen`.*',
'`u`.`nama_univ` AS `nama_univ`',
'`j`.`singkatan` AS `singkatan`'
),
'join' => 'JOIN `Penilaian` AS `pen` ON `pen`.`no_test` = `t`.`no_test` JOIN `Universitas` AS `u` ON `u`.`id` = `t`.`no_test` JOIN `Jurusan` AS `j` ON `j`.`id` = `t`.`no_test`',
)
));

CakePHP 3 - How do I use left joins in a query

I have the following query that works, but after talking to the client I realized I need left joins to get the desired results and I don't know how to do it.
This is my query:
$query = $this->AssetStatusAudits->find('all', [
'contain' => [
'AssetStatus',
'Users',
'Assets' => function ($q) {
return $q->contain([
'Employees',
'Sites'
]);
}
],
'conditions' => [
'AssetStatusAudits.created >' => $from,
'AssetStatusAudits.created <' => $to
]
]);
$query->select([
'createdDate' => 'date(AssetStatusAudits.created)',
'assetStatus' => 'AssetStatus.desc_en',
'firstName' => 'Users.first_name',
'lastName' => 'Users.last_name',
'count' => $query->func()
->count('*')
])
->group('date(AssetStatusAudits.created)', 'assetStatus.desc_en', 'users.last_name')
->order('Users.last_name', 'Users.created');
The above query generates this in cake:
SELECT date(AssetStatusAudits.created) AS `createdDate`,
AssetStatus.desc_en AS `assetStatus`,
Users.first_name AS `firstName`,
Users.last_name AS `lastName`,
(COUNT(*)) AS `count`
FROM asset_status_audits AssetStatusAudits
INNER JOIN asset_status AssetStatus ON AssetStatus.id = (AssetStatusAudits.asset_status_id)
INNER JOIN users Users ON Users.id = (AssetStatusAudits.user_id)
INNER JOIN assets Assets ON Assets.id = (AssetStatusAudits.asset_id)
LEFT JOIN employees Employees ON Employees.id = (Assets.employee_id)
INNER JOIN sites Sites ON Sites.id = (Assets.site_id)
WHERE (AssetStatusAudits.created > date('2016-01-13') AND AssetStatusAudits.created < date('2016-05-03'))
GROUP BY date(AssetStatusAudits.created)
ORDER BY Users.last_name
But this is the query that I need to add to cakePHP and I don't know how to do it:
SELECT
date(asset_tracking.asset_status_audits.created) as 'Date',
asset_tracking.asset_status.desc_en as 'Status',
asset_tracking.users.first_name as 'First Name' ,
asset_tracking.users.last_name as 'Last Name',
count(*)
FROM asset_tracking.asset_status_audits
LEFT OUTER JOIN asset_tracking.assets ON asset_tracking.asset_status_audits.asset_id = asset_tracking.assets.id
LEFT OUTER JOIN asset_tracking.asset_status ON asset_tracking.asset_status_audits.asset_status_id = asset_tracking.asset_status.id
LEFT OUTER JOIN asset_tracking.users ON asset_tracking.asset_status_audits.user_id = asset_tracking.users.id
LEFT OUTER JOIN asset_tracking.employees ON asset_tracking.assets.employee_id = asset_tracking.employees.id
LEFT OUTER JOIN asset_tracking.sites ON asset_tracking.assets.site_id = asset_tracking.sites.id
WHERE asset_tracking.asset_status_audits.created between date('2016-01-13') and date('2016-05-19')
group by
date(asset_tracking.asset_status_audits.created) ,
asset_tracking.asset_status.desc_en,
asset_tracking.users.last_name
ORDER BY asset_tracking.users.last_name, asset_tracking.users.created;