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;
Related
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
------------^
Im trying to search in multiple associated tables with the matching() function.
I can't seem to incorporate 'OR' in this search query, the following code seems to be working but seems only to match if there is LIKE %search% in all the associated tables.
Help is greatly appreciated.
if($this->request->is(['post','put']))
{
$search = $this->request->data['search'];
/* Conditions for this table query */
$this->listConditions['Purchases.created LIKE'] = '%$'.$search.'%';
$contain = ['Customers','Users','Professions.ProfessionsLanguages','Cities'];
/* Conditions for associated table queries */
$customerConditions = [
'Customers.email LIKE' => '%'.$search.'%',
'Customers.city LIKE' => '%'.$search.'%',
'Customers.company_name LIKE' => '%'.$search.'%',
'Customers.organization_number LIKE' => '%'.$search.'%',
];
$userConditions = [
'Users.email LIKE' => '%'.$search.'%',
'Users.first_name LIKE' => '%'.$search.'%',
'Users.last_name LIKE' => '%'.$search.'%',
];
$profProflanguagesConditions = ['ProfessionsLanguages.name LIKE' => '%'.$search.'%'];
$citiesConditions = ['Cities.name LIKE' => '%'.$search.'%'];
/* Perform queries */
$query = $this->Purchases->find('all')->where($this->listConditions)->contain($contain);
$query->matching('Customers', function ($q) use ($customerConditions) {
return $q->where($customerConditions);
});
$query->matching('Users', function ($q) use ($userConditions) {
return $q->where($userConditions);
});
$query->matching('Professions.ProfessionsLanguages', function ($q) use ($profProflanguagesConditions) {
return $q->where($profProflanguagesConditions);
});
$query->matching('Cities', function ($q) use ($citiesConditions) {
return $q->where($citiesConditions);
});
debug($query->toArray());
die();
}
I've tried matching conditions like this:
$customerConditions = [
'OR' => [
['Customers.email LIKE' => '%'.$search.'%'],
['Customers.city LIKE' => '%'.$search.'%'],
['Customers.company_name LIKE' => '%'.$search.'%'],
['Customers.organization_number LIKE' => '%'.$search.'%'],
]
];
$userConditions = [
'OR' => [
['Users.email LIKE' => '%'.$search.'%'],
['Users.first_name LIKE' => '%'.$search.'%'],
['Users.last_name LIKE' => '%'.$search.'%'],
]
];
But only works for first matching() call.
This is the query with 'OR' in matching conditions.
SELECT
Purchases.id AS `Purchases__id`,
Purchases.customer_id AS `Purchases__customer_id`,
Purchases.user_id AS `Purchases__user_id`,
Purchases.invoice_id AS `Purchases__invoice_id`,
Purchases.status AS `Purchases__status`,
Purchases.created AS `Purchases__created`,
Purchases.quantity AS `Purchases__quantity`,
Purchases.quantity_max AS `Purchases__quantity_max`,
Customers.id AS `Customers__id`,
Customers.organization_number AS `Customers__organization_number`,
Customers.company_name AS `Customers__company_name`,
Customers.address AS `Customers__address`,
Customers.address2 AS `Customers__address2`,
Customers.zipcode AS `Customers__zipcode`,
Customers.city AS `Customers__city`,
Customers.email AS `Customers__email`,
Customers.created AS `Customers__created`,
Customers.removed AS `Customers__removed`,
Users.id AS `Users__id`,
Users.customer_id AS `Users__customer_id`,
Users.type AS `Users__type`,
Users.email AS `Users__email`,
Users.password AS `Users__password`,
Users.salt AS `Users__salt`,
Users.first_name AS `Users__first_name`,
Users.last_name AS `Users__last_name`,
Users.invoice_text AS `Users__invoice_text`,
Users.created AS `Users__created`,
Users.removed AS `Users__removed`,
Professions.id AS `Professions__id`,
Professions.parent_id AS `Professions__parent_id`,
Professions.lft AS `Professions__lft`,
Professions.rght AS `Professions__rght`,
ProfessionsPurchases.id AS `ProfessionsPurchases__id`,
ProfessionsPurchases.profession_id AS `ProfessionsPurchases__profession_id`,
ProfessionsPurchases.purchase_id AS `ProfessionsPurchases__purchase_id`,
ProfessionsLanguages.id AS `ProfessionsLanguages__id`,
ProfessionsLanguages.profession_id AS `ProfessionsLanguages__profession_id`,
ProfessionsLanguages.language_id AS `ProfessionsLanguages__language_id`,
ProfessionsLanguages.name AS `ProfessionsLanguages__name`,
Cities.id AS `Cities__id`,
Cities.state_id AS `Cities__state_id`,
Cities.name AS `Cities__name`,
Cities.active AS `Cities__active`,
Cities.applicant_count AS `Cities__applicant_count`,
CitiesPurchases.id AS `CitiesPurchases__id`,
CitiesPurchases.city_id AS `CitiesPurchases__city_id`,
CitiesPurchases.purchase_id AS `CitiesPurchases__purchase_id`
FROM
purchases Purchases
INNER JOIN
customers Customers
ON (
(
Customers.email like :c0
OR Customers.city like :c1
OR Customers.company_name like :c2
OR Customers.organization_number like :c3
)
AND Customers.id = (
Purchases.customer_id
)
)
INNER JOIN
users Users
ON (
(
Users.email like :c4
OR Users.first_name like :c5
OR Users.last_name like :c6
)
AND Users.id = (
Purchases.user_id
)
)
INNER JOIN
professions Professions
ON 1 = 1
INNER JOIN
professions_purchases ProfessionsPurchases
ON (
Purchases.id = (
ProfessionsPurchases.purchase_id
)
AND Professions.id = (
ProfessionsPurchases.profession_id
)
)
INNER JOIN
professions_languages ProfessionsLanguages
ON (
ProfessionsLanguages.language_id = :c7
AND ProfessionsLanguages.name like :c8
AND Professions.id = (
ProfessionsLanguages.profession_id
)
)
INNER JOIN
cities Cities
ON Cities.name like :c9
INNER JOIN
cities_purchases CitiesPurchases
ON (
Purchases.id = (
CitiesPurchases.purchase_id
)
AND Cities.id = (
CitiesPurchases.city_id
)
)
WHERE
(
(
Purchases.user_id
) IS NOT NULL
AND (
Purchases.customer_id
) IS NOT NULL
)
I've checked the woocommerce reports and products that haven't been sold are being fetched in the query?
Here is the query:
SELECT wp_terms.name as categoryname,v1.meta_value as thevalue, wp_terms.slug as categoryslug, wp_posts.post_title as mytitle, wp_terms.term_id as categoryid,wp_term_taxonomy.parent as categoryparent FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
INNER JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id)
INNER JOIN wp_postmeta v1 ON (wp_posts.ID = v1.post_id) AND v1.meta_key LIKE 'total_sales'
WHERE wp_posts.post_status = 'publish' AND wp_posts.post_type = 'product' AND wp_terms.slug='garden-lighting' AND wp_posts.post_title NOT LIKE '%cable%' AND v1.meta_value !=0
ORDER BY v1.meta_value DESC
LIMIT 8
I checked the results of the array returned and products that haven't been sold are returning with a total_sales value?
Where did i go wrong? I want products returned for a specific category and ordered by total sales.
Why not use WP_Query instead of trying to write an SQL statement?
If I've understood you correctly, the following should return the first 8 posts in the 'garden-lighting' category sorted by sales and then by title.
$args = array(
'query_id' => 'exclude_cable',
'post_type' => 'product',
'post_status' => 'publish',
'category_name' => 'garden-lighting',
'posts_per_page' => 8,
'orderby' => array( 'meta_value_num' => 'DESC', 'title' => 'ASC' ),
'meta_key' => 'total_sales'
);
$new_query = new WP_Query( $args );
Edit I have added a few extra parameters. One I forgot to designate the product post type! Oops. But additionally, I have added a query_id parameter. WordPress doesn't do anything with this by default, but we can filter the posts_where clause and use it there to only modify the posts_where for this specific query.
add_filter( 'posts_where' , 'so_28478323_posts_where', 10, 2 );
function so_28478323_posts_where( $where, $q ) {
if ( 'exclude_cable' == $q->get( 'query_id', null ) ) {
$where .= " AND wp_posts.post_title NOT LIKE '%cable%'";
}
return $where;
}
The following QueryOver generates the Subquery in the Where block but i was rather looking for the way to specify that condition on the join statement
var productsWithLatestComments = _sessionHelper.GetSession().QueryOver(() => p)
.Left.JoinAlias(() => p.Comments, () => cm)
.WithSubquery.Where(() => cm.CommentDate == QueryOver.Of<Comment>()
.Where(c => c.Product.Id == p.Id)
.SelectList(list => list.SelectMax(c => c.CommentDate)).As<DateTime>())
.Where(() => p.Status != "NOT SOLD" )
.SelectList(list => list ....GET THE LIST OF COLS.........
This GENERATES something like
SELECT this_.id as y0_, ......... FROM product this_
left outer join comment cn1_ on this_.id=cn1_.product_id
WHERE cn1_.comment_date = (SELECT max(this_0_.created_date) as y0_ FROM comment this_0_ WHERE this_0_.product_id = this_.id) and (not (this_.status = ?p0);?p0 = 'Sold Out'' [Type: String (18)]
But i was looking for
SELECT this_.id as y0_, ......... FROM product this_
left outer join comment cn1_ on this_.id=cn1_.product_id and cn1_.comment_date = (SELECT max(this_0_.created_date) as y0_ FROM comment this_0_ WHERE this_0_.product_id = this_.id)
WHERE (not (this_.status = ?p0);?p0 = 'Sold Out'' [Type: String (18)]
Ok i got it with some changes in the QueryOver by specifying the subquery inside the join alias rather than inside .WithSubquery
var productsWithLatestComments = _sessionHelper.GetSession().QueryOver(() => p)
.JoinAlias(() => p.Comments, () => cm, JoinType.LeftOuterJoin, Subqueries.Where(() => cm.CommentDate == QueryOver.Of<Comment>()
.Where(c => c.Product.Id == p.Id)
.SelectList(list => list.SelectMax(c => c.CommentDate)).As<DateTime>()))
.Where(() => p.Status != "NOT SOLD" )
.SelectList(list => list ....GET THE LIST OF COLS.........
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