cakephp 3.4 mySQL to orm convert - mysql

my Current MYSQL query is
SELECT
cl.user_id,
COUNT(q.id) as completed_questions,
(
SELECT
SUM(points)
FROM
completed_levels
WHERE
user_id = cl.user_id
)
as level_point
FROM
completed_levels cl
JOIN
questions q
on q.level_id = cl.level_id
GROUP BY
cl.user_id;
my current ORM is following i just not able to handle select part in
$completedLevels = TableRegistry::get('CompletedLevels');
$completedLevels = $completedLevels->find('All');
$completedLevels = $completedLevels
->contain(['Users', 'Levels'])
->select([
'user_name' => 'Users.name',
'count_questions' => 'COUNT(Questions.id)',
'total_pints' => [
'select'=>'SUM(CompletedLevels.points)'
]
])
->join([
'table' => 'Questions',
'conditions' => 'Questions.level_id = CompletedLevels.level_id',
])
->group(['CompletedLevels.user_id'])
->all();

Found answer
ITS "SUB-Query"
$completedLevels = TableRegistry::get('CompletedLevels');
TableRegistry::config('cl', ['table' => 'completed_levels']);
$cl = TableRegistry::get('cl');
$cl = $cl->find('all');
$cl ->select($cl->func()->sum('points'));
$completedLevels = $completedLevels->find('All');
$completedLevels = $completedLevels
->contain(['Users', 'Levels'])
->select([
'user_name' => 'Users.name',
'count_questions' => 'COUNT(Questions.id)',
'total_pints' => $cl->where('user_id = CompletedLevels.user_id')
])->join([
'table' => 'Questions',
'conditions' => 'Questions.level_id = CompletedLevels.level_id',
])->group(['CompletedLevels.user_id']);

Related

I need mysql query for wordpress for get ordered list

I need to get ordered list by three fields.
$sql = "
SELECT
SQL_CALC_FOUND_ROWS $wpdb->posts.ID
FROM
$wpdb->posts
INNER JOIN
$wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )
INNER JOIN
$wpdb->postmeta AS mt1 ON ( $wpdb->posts.ID = mt1.post_id )
WHERE
1=1
AND
(
( mt1.meta_key = 'pub_series' AND mt1.meta_value = 'Book' )
OR ( mt1.meta_key = 'pub_series' AND mt1.meta_value = 'Book chapter' )
OR ( mt1.meta_key = 'pub_series' AND mt1.meta_value = 'Journal Article' )
)
/*AND
(
mt3.meta_key = 'forthcoming'
)*/
AND
$wpdb->postmeta.meta_key = 'pub_year'
AND
$wpdb->posts.post_type = 'publication'
AND
$wpdb->posts.post_status = 'publish'
GROUP BY
$wpdb->posts.ID
ORDER BY
/*FIELD(mt3.meta_key, 'forthcoming') DESC,
FIELD(mt3.meta_value, 'null') DESC,*/
//FIELD($wpdb->postmeta.meta_value,1),
$wpdb->postmeta.meta_value DESC,
$wpdb->posts.post_date DESC
";
$total = count($wpdb->get_results($sql));
$offset = ( $paged * $posts_per_page ) - $posts_per_page;
$results = $wpdb->get_results( $sql . "
LIMIT
$offset, $posts_per_page" );
This is query ordered list by two fields: [custom_field] pub_year (possible values 2018, 2017...) and [delautl wp post date field] post_date. It is ok.
But now I need to show items with [custom_field] forthcoming = 1. Problem that there three states if this field:
- items with forthcoming = 1
- items with forthcoming = 0
- and items where custom field forthcoming not exist
I need to get ordered list with firts items forthcoming = 1 and other should be ordered by pub_year and date. How I can do this. Tell me if you need some more info. Thanks a lot.
I was get needed ordered list with adding for all posts meta key forthcoming = 0 with update meta method. So all fields have this field.
Next I was used wp_query meta_query args:
$pub_series = 'Book,Book chapter,Journal Article';
$search_args = array();
if (!empty($pub_series)) {
$pub_series_arr = explode(",", $pub_series);
if (!empty($pub_series_arr)) {
$search_args_add = array(
'relation' => 'OR'
);
foreach ($pub_series_arr as $pub_series_el) {
$adv_search_query_el = trim($pub_series_el);
if (!empty($adv_search_query_el)) {
$search_args_add[] = array(
'key' => 'pub_series',
'value' => $adv_search_query_el,
'compare' => '='
);
}
}
$search_args['meta_query'][] = $search_args_add;
}
}
$search_args['meta_query'][] = array(
'relation' => 'OR',
'forthcoming_clause' => array(
'key' => 'forthcoming',
'value' => '1'
),
'forthcoming_clause0' => array(
'key' => 'forthcoming',
'value' => '0'
)
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'post_type' => 'publication',
'post_status' => 'publish',
'posts_per_page' => 10,
'orderby' => array(
'forthcoming_clause' => 'DESC',
'meta_value' => 'DESC',
'date' => 'DESC'
),
'meta_key' => 'pub_year',
'paged' => $paged
);
$args = array_merge($args, $search_args);
$posts = new WP_Query( $args );
if ( $posts->have_posts() ) : ...

CakePHP multiple matching() conditions with OR

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
)

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 LEFT JOIN on multiple tables with condition

I want to use this CakePHP form to do a LEFT join. See CakePHP Book - section on Joining Tables
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$Item->find('all', $options);
EXCEPT that my LEFT JOIN has a dependent table with conditions. In MySQL the join looks like this
LEFT JOIN (
channels as Channel
INNER JOIN regions as Region ON ( Region.id = Channel.region_id and Region.id=1 )
) ON Channel.id = Item.channel_id
Can I do the same thing in CakePHP 2.0 using the $options['joins'] syntax?
So after a bit of fiddling, I discovered this does the "trick" in CakePHP. According to SQL EXPLAIN, this is a much faster join than using a sub-query to force conditions on the LEFT join table
$options['joins'] = array(
array('table' => '(channels as `Channel` INNER JOIN regions as `Region`
ON ( `Region`.id = `Channel`.region_id and `Region`.id=1 ))',
// 'alias' => 'Channel', // the alias is 'included' in the 'table' field
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$Item->find('all', $options);
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
'Region.id' = 1
)
)
);
$Item->find('all', $options);
The condition key in joins options can work too
A bit late but for those who will see this through google like me you should try the following.
$options['joins'] = array(
array(
'table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Item.channel_id = Channel.id'
)
),
array(
'table' => 'regions',
'alias' => 'Region',
'type' => 'INNER',
'conditions' => array(
'Channel.region_id = Region.id',
'Region.id = 1'
)
)
);