How to convert custom query to CDbCriteria - php

I have the following query:
select
`t`.`id` AS `id`,
`rm`.`role_id` AS `role_id`,
`t`.`id` AS `sequence`,
`t`.`parent_id` AS `parent_id`,
`t`.`label` AS `label`,
`t`.`order` AS `order`,
(case
when isnull(`rm`.`id`) then 0
else 1
end) AS `description`,
`tb`.`label` AS `parent_label`
from
((`tbl_menu` `t`
left join `tbl_menu` `tb` ON ((`t`.`parent_id` = `tb`.`id`)))
left join `tbl_role_menu` `rm` ON ((`rm`.`menu_id` = `t`.`id`))) and rm.role_id = $role_id
where
isnull(`tb`.`label`)
union select
`t`.`id` AS `id`,
`rm`.`role_id` AS `role_id`,
`t`.`parent_id` AS `parent_id`,
`t`.`parent_id` AS `sequence`,
`t`.`label` AS `label`,
`t`.`order` AS `order`,
(case
when isnull(`rm`.`id`) then 0
else 1
end) AS `description`,
`tb`.`label` AS `parent_label`
from
((`tbl_menu` `t`
left join `tbl_menu` `tb` ON ((`t`.`parent_id` = `tb`.`id`)))
left join `tbl_role_menu` `rm` ON ((`rm`.`menu_id` = `t`.`id`))) and rm.role_id = $role_id
where
(`tb`.`label` is not null)
order by `sequence` , `parent_id` , `label`
On both queries, on the second left join I have to pass a variable $role_id. Currently, I have this query on a view but if a try passing a criteria condition, the resulting query is
select * form menu_links where role_id = $role_id
Being menu_links the name of the view. This doesn't give me the result I want. I need a way to add this parameter to this query and transform it into a CDbCriteria in order to pass it to a CGridView. Any help?
Thanks.

Consider using CArrayDataProvider.
CArrayDataProvider acts as a wrapper around a simple associative array and CGridView won't know the difference. You can even apply pagination, sorting etc. An example showcasing these features can be found in the documentation:
$rawData=Yii::app()->db->createCommand('SELECT * FROM tbl_user')->queryAll();
$dataProvider=new CArrayDataProvider($rawData, array(
'id'=>'user',
'sort'=>array(
'attributes'=>array(
'id', 'username', 'email',
),
),
'pagination'=>array(
'pageSize'=>10,
),
));

I give you a simple example you will figure out how to apply it to you case
$sql= "select * form menu_links where role_id = :role_id";
$role_id='Something you will get from your could';
$command = Yii::app()->db->createCommand($sql);
// And finally the command you can replace the role id with varibale is
$command->bindParam(":role_id", $role_id, PDO::PARAM_STR);
$result = $command->queryAll();
I hope this was what you were asking.

Related

Why Codeigniter's Query Builder is returning this MySQL query wrong and twice?

I'm getting this string (raw copy and paste)
SELECT `ing_names`.`name` FROM `ingredients` INNER JOIN `ing_names` ON `ingredients`.`id_name` = `ing_names`.`id` WHERE `id_type` = '1'
SELECT `ing_names`.`name` FROM `ingredients` INNER JOIN `ing_names` ON `ingredients`.`id_name` = `ing_names`.`id` WHERE `id_type` = '1'
From this test code (in my model)
$this->db->select('ing_names.name','ingredients.stock');
$this->db->from('ingredients');
$this->db->join('ing_names','ingredients.id_name = ing_names.id', 'inner');
$this->db->where('id_type','1');
$this->db->get();
echo $this->db->last_query();
Why is query builder returning this query?
I'm trying to do this query
SELECT `ing_names`.`name`, `ingredients`.`stock`
FROM `ingredients`
INNER JOIN `ing_names`
ON `ingredients`.`id_name` = `ing_names`.`id`
WHERE `id_type` = 1
First argument to select should be a string or an array.
$this->db->select('ing_names.name, ingredients.stock');
...
//$this->db->select(['ing_names.name', 'ingredients.stock']);
Second argument to select specifies whether to escape values or not.

Yii2 translating findBySql query to QueryBuilder query

I have the following query using findbysql:
$query = Users::findBySql('select a.user_id, a.last_name,a.first_name, a.emp_id, ar.role_id from auth_users a, auth_user_roles AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
where AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND (ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)
UNION
SELECT DISTINCT a.user_id, a.last_name, a.first_name, a.emp_id, NULL AS role_id FROM auth_users a, AUTH_USER_ROLES AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
WHERE AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND
AR.ACCESS_END_DATE < SYSDATE AND AR.USER_ID NOT IN (select USER_ID from auth_user_roles where ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)', [':dept_group_id' => $dept_group_id ]);
This query does exactly what I want it to, but the problem is when I try to put it into a gridview it does not sort. According to Sort and search column when I'm querying with findbysql in yii2 it seems like I need to use query builder instead.
So I was trying to do that with the first part of my query (before the union), and it looks like so:
$query1 = (new \yii\db\Query())
->select(['user_id', 'last_name', 'first_name', 'emp_id'])
->from('AUTH_USERS');
$query2 = (new \yii\db\Query())
->select('USER_ID')
->from('AUTH_USER_ROLES')
->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
$query = $query1->innerJoin('AUTH_USER_DEPTS', 'AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id')->innerJoin('DEPARTMENTS', 'AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id');
$query->innerJoin('AUTH_USER_ROLES', 'AUTH_USER_ROLES.USER_ID = auth_users.USER_ID')->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
However, my query comes out like this in yii and apparently oracle is not accepting the double quotes around the column names:
SELECT "user_id", "last_name", "first_name", "emp_id" FROM "AUTH_USERS"
INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id
INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id
INNER JOIN "AUTH_USER_ROLES" ON AUTH_USER_ROLES.USER_ID = auth_users.USER_ID
WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL
I know the query might be incorrect here already but I cant even get the double quotes to go away. Tried defining the select statements multiple ways suggested by the yii docs already with no success:
select(['user_id', 'last_name', 'first_name', 'emp_id'])
select('user_id', 'last_name', 'first_name', 'emp_id')
select("user_id, last_name,first_name,emp_id")
I have also tried joining the queries like this from the docs: http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
$query = $query1->innerJoin(['u' => $query2], 'u.user_id = user_id');
but it also complains that it doesnèt recognize u and the query instead comes out like so in yii:
SELECT COUNT(*) FROM "AUTH_USERS" INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id INNER JOIN (SELECT "USER_ID" FROM "AUTH_USER_ROLES" WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL) "u" ON u.user_id = auth_users.user_id
At this point im just looking for the easiest way to build this query (whether it be using querybuilder or some other way) so that I can pass the query to my gridview and sort it.
I would recommend you first create all the data models you need from the tables you need for the query, using Gii it should be easy and it even creates the relationships you will need.
After that, you can do something like the following:
$query = Users::find()
->joinWith('theRelation1Name')
->joinWith('theRelation2Name')
->joinWith('theRelation3Name')
...
This way you don't need to give tables aliases or add the conditions needed for the relations to work.

codeigniter $this->db->query JOIN WHERE not working

This my screenshot problem I have
I have the following codes in my view.
$jumlah = $this->db->query("
SELECT * FROM actor
JOIN film_actor ON film_actor.actor_id=actor.actor_id
JOIN film ON film.film_id=film_actor.film_id
JOIN film_category ON film_category.film_id=film.film_id
JOIN category ON category.category_id=film_category.category_id
WHERE first_name like $u->first_name AND last_name like $u->last_name");
?>
why my query not working? I think I have done with that code, but why I am getting error message.
Sorry, i can't describe my problem so detail, but i have image for describe that.
$array = array('first_name' => $u->first_name, 'last_name' => $u->last_name);
$jumlah = $this->db->select('*')->from('actor');
$this->db->join('film_actor', 'film_actor.actor_id=actor.actor_id');
$this->db->join('film', 'film.film_id=film_actor.film_id');
$this->db->join('film_category', 'film_category.film_id=film.film_id');
$this->db->join('category', 'category.category_id=film_category.category_id ');
$this->db->like($array); // WHERE `first_name` LIKE '%$u->first_name%' AND `last_name` LIKE '%$u->last_name%'

Sorting UNION queries with Laravel 4.1

I think there is something changed in the union between Laravel 4 and Laravel 4.1. I have 2 models.
$photos = DB::table('photos')->select('id', 'name', 'created_at');
$videos = DB::table('videos')->select('id', 'name', 'created_at');
I want to union the 2 querys and order the 2 querys with the created_at field.
$photos = $photos->orderBy('created_at', 'desc');
$combined = $photos->union($videos);
With Laravel 4 it gives me this query:
select `id`, `name`, `created_at` from `videos`
union
select `id`, `name`, `created_at` from `photos`
order by `created_at` desc
This works ok, it sorts the results for both querys together. In Laravel 4.1 it gives me this query:
(select `id`, `name`, `created_at` from `videos`)
union
(select `id`, `name`, `created_at` from `photos` order by `created_at` desc)
This results in a list of videos and after that an ordered list of photos. I need to have a list where the to combined querys are sorted. I want Laravel to give me this query:
(select `id`, `name`, `created_at` from `videos`)
union
(select `id`, `name`, `created_at` from `photos`)
order by `created_at` desc
How do get this working in Laravel?
This i believe is a bug and is not fixed yet. I have the same issue when trying to sort union queries.
$query1->union($query2)->orderBy('foo','desc')
causes the order by clause to be added to $query 1 alone.
Adding orderBy individually to $query1 and $query2 and then doing a union like below
$query1->orderBy('foo desc');
$query2->orderBy('foo desc');
$query1->union($query2);
This obviously works but it does not produce the same result as doing a orderBy on the union's result.
For now, the workaround seem to be doing something like
$query = $query1->union($query2);
$querySql = $query->toSql();
$query = DB::table(DB::raw("($querySql order by foo desc) as a"))->mergeBindings($query);
This would produce a query like:
select * from (
(select a as foo from foo)
union
(select b as foo from bar)
) as a order by foo desc;
And that does the trick.
I don't really know Laravel, but I'll bet this will do it:
$photos = DB::table('photos')->select('id', 'name', 'created_at');
$videos = DB::table('videos')->select('id', 'name', 'created_at');
$combined = $photos->union($videos)->orderBy('created_at', 'desc');
It seems to be fixed in this pull request: https://github.com/laravel/framework/pull/3901
It should work if you add orderBy methods in the chaining to both of them, like this:
$photos = DB::table('photos')->select('id', 'name', 'created_at')->orderBy('created_at', 'desc');
$videos = DB::table('videos')->select('id', 'name', 'created_at')->orderBy('created_at', 'desc');
$combined = $photos->union($videos);
Right now, as Barmar said, Laravel only knows that the photos query should be ordered, since you do that in your third line, which can be removed if you do it like above.
You can try with DB::query() like below:
DB::query('(Select id,name,created_at from photos)
union
(Select id,name,created_at from videos) order by created_at ASC');
I guess as of know it will work. Still looking for actual solution!
You can use fromSub to create a sub query of unions. I find this much cleaner than using mergeBindings.
$photos = DB::table('photos')->select('id', 'name', 'created_at');
$videos = DB::table('videos')->select('id', 'name', 'created_at')->union($photos);
$result = DB::query()->fromSub($querySql, 'a')->orderBy('year', 'desc')->get();

How to convert normal sql query to Zend_Db_Select?

Hi I want to convert my normal mysql query to zend.db.select;
I want to use this script:
$select = $db->select();
// Add a FROM clause
$select->from( ...specify table and columns... )
// Add a WHERE clause
$select->where( ...specify search criteria... )
// Add an ORDER BY clause
$select->order( ...specify sorting criteria... );
$select->limit(20, 10);
for my query below
SELECT
IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid) friend1,c.UserName,
derived_messages.message, derived_messages.fromid, derived_messages.toid,
derived_messages.is_read,derived_messages.type,derived_messages.id as mesid,
derived_messages.date,
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1) as MesMapid
FROM
(
SELECT *
FROM messages
WHERE messages.deleted_by NOT
IN ( $user )
ORDER BY Date DESC
) derived_messages
INNER JOIN Users c ON c.MemberID = IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid)
WHERE (derived_messages.id IN
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1)
AND
(derived_messages.toid='$user' OR derived_messages.fromid='$user'))
GROUP BY friend1 ASC
ORDER BY derived_messages.date DESC, derived_messages.id DESC LIMIT $limit $offset
I hope someone can help m on this.
Thank you.
It's possible but unlikely someone will write the query for you.
My recommendation on tackling such a query is to write each individual subquery as its own Zend_Db_Select object and then build the final query using the subqueries that you already have objects for.
Zend_Db_Select doesn't directly support the IF function, so for that you will need to use Zend_Db_Expr to add that statement into your select.
Here is a basic example of what I am talking about. Let's build the following query:
SELECT IF(msg.toId = 'drew010', msg.fromId, msg.toId), id, name, age, history.ip
FROM users
JOIN history ON users.id = history.userId
WHERE users.id = (
SELECT id FROM users WHERE loginCount > 1000
)
GROUP BY id,
ORDER BY age DESC
First build the subselect that select users where loginCount > 1000.
$subquery1 = $db->select()
->from('users', array('id'))
->where('loginCount > ?', 1000);
Next, build the outer query with the IF function:
$cols = array(
new Zend_Db_Expr('IF(' . $db->quoteInto('msg.toId = ?', 'drew010') . '), msg.fromId, msg.toId'),
'id', 'name', 'age'
);
$query = $db->select()
->from('users', $cols)
->join('history', 'users.id = history.userId', array('ip'))
->where('id = ?', $subquery1)
->group('id')
->order('age DESC');
echo $query;
The output:
SELECT
IF(msg.toId = 'drew010', msg.fromId, msg.toId),
`users`.`id`,
`users`.`name`,
`users`.`age`,
`history`.`ip`
FROM `users`
INNER JOIN `history`
ON users.id = history.userId
WHERE id = (
(SELECT `users`.`id`
FROM `users`
WHERE (loginCount > 1000))
)
GROUP BY `id`
ORDER BY `age` DESC
So the way to go is break the entire query into individual queries first, and then construct the outer query. Just have patience and take it slow. That and read over the Zend_Db_Select docs to get a full picture of what you have available to you.

Categories