I'm new in Yii2, and I have a query with right result:
SELECT DISTINCT workloadTeam.project_id, wp.project_name, workloadTeam.user_id, workloadTeam.commit_time, wp.workload_type FROM
(SELECT p.id, p.project_name, w.user_id, w.commit_time, w.comment, w.workload_type
FROM workload as w, project as p
WHERE w.user_id = 23 AND p.id = w.project_id) wp
INNER JOIN workload as workloadTeam ON wp.id = workloadTeam.project_id
But in my ModelSearch.php, I wrote:
$user_id = Yii::$app->user->id;
$subquery = Workload::find()->select('p.id', 'p.project_name', 'w.user_id', 'w.commit_time', 'w.comment', 'w.workload_type')
->from(['project as p', 'workload as w'])
->where(['user_id' => $user_id, 'p.id' => 'w.project_id']);
$query = Workload::find()
->select(['workloadTeam.project_id', 'wp.project_name', 'workloadTeam.user_id', 'workloadTeam.from_date', 'workloadTeam.to_date', 'workloadTeam.workload_type', 'workloadTeam.comment'])
->where(['', '', $subquery]);
$query->join('INNER JOIN', 'workload as workloadTeam', 'wp.id = workloadTeam.project_id');
It happended error:
SELECT COUNT(*) FROM `workload` INNER JOIN `workload` `workloadTeam` ON wp.id = workloadTeam.project_id WHERE `` (SELECT p.project_name `p`.`id` FROM `project` `p`, `workload` `w` WHERE (`user_id`=20) AND (`p`.`id`='w.project_id'))
And I can't fix it with right query above.
You have any solution about this?
Is this error shown in the Yii-debug toolbar? Then your query (which you mentioned as error) is probably only the count from the query which is listed before.
You missed to add the sub-query in from clause like you shown in your working sql. Add this in your where clause were just the wrong place. Put sub-queries in whereconditions, if you have scalar results, because you have to use this result with operands like =, >=, in...
This could work:
$user_id = Yii::$app->user->id;
$subquery = Workload::find()->select([
'p.id as id',
'p.project_name as project_name',
'w.user_id as user_id',
'w.commit_time as commit_time',
'w.comment as comment',
'w.workload_type as workload_type'
])
->from([
'project as p',
'workload as w'
])
->where([
'user_id' => $user_id,
'p.id' => 'w.project_id'
]);
$query = Workload::find()
->select([
'workloadTeam.project_id',
'wp.project_name',
'workloadTeam.user_id',
'workloadTeam.from_date',
'workloadTeam.to_date',
'workloadTeam.workload_type',
'workloadTeam.comment'
])
->from([$subquery => 'wp']); //you were missing this line
$query->join('INNER JOIN', 'workload as workloadTeam', 'wp.id = workloadTeam.project_id');
But you don't use any selects from your workload table in your main-query $query...
Since I don't know what's your goal to achieve I can't help you at this topic...
Related
How can I convert this raw query into query builder yii2 as I am getting the record using sub-query:
RAW QUERY:
SELECT *
FROM (
SELECT DISTINCT `comp`.*,TIMESTAMPDIFF(HOUR,comp.created_date,comp.updated_date)
AS hours
FROM `complaints` `comp`
INNER JOIN `complaint_log` `comp_log` ON comp_log.`comp_id` = comp.`id`
WHERE ((comp.name LIKE '%%' OR comp.id LIKE '%%' OR comp.phone_no LIKE '%%')
AND DATE(comp.created_date)
BETWEEN '2018-01-01' AND '2020-03-20')
AND (comp.is_delete = 0)
ORDER BY `comp`.`id` DESC, `comp`.`created_date` DESC)
AS cte_name WHERE hours > 120;
Yii2 Query
$query = (new \yii\db\Query())
->select('comp.*')
->from('complaints comp
->distinct()
->innerJoin('complaint_log as comp_log', 'comp_log.`comp_id` =comp.`id`')
->where($search)
->andWhere('comp.is_delete = 0')
->orderBy("comp.id DESC")
->addOrderBy('comp.created_date DESC');
Try following code:
$subquery = (new \yii\db\Query())
->select(['comp.*', 'TIMESTAMPDIFF(HOUR, comp.created_date, comp.updated_date) AS hours'])
->distinct()
->from('complaints comp')
->innerJoin('complaint_log comp_log', 'comp_log.comp_id = comp.id')
->where(['or',
['like', 'comp.name', $search_name],
['or',
['like', 'comp.id', $search_id],
['like', 'comp.phone_no', $search_phone],
]
])
->andWhere('DATE(comp.created_date) BETWEEN :cStart AND :cEnd', [':cStart' => '2018-01-01', ':cEnd' => '2020-03-20'])
->andWhere(['comp.is_delete' => 0])
->orderBy(['comp.id' => SORT_DESC, 'comp.created_date' => SORT_DESC])
;
$query = (new \yii\db\Query())
->select('cte_name.*')
->from(['cte_name' => $subquery])
->where(['>', 'cte_name.hours', 120])
;
You can use createCommand() function: use below query.
$connection = \Yii::$app->db;
$query = $connection->createCommand(
'
SELECT * FROM (
SELECT DISTINCT comp.*,TIMESTAMPDIFF(HOUR,comp.created_date,comp.updated_date) AS hours
FROM complaints comp
INNER JOIN complaint_log comp_log ON comp_log.comp_id = comp.id
WHERE ('.$search.')
AND (comp.is_delete = 0)
ORDER BY comp.id DESC, comp.created_date DESC
) AS cte_name WHERE hours > 120;
');
$data = $query->queryAll();
Put your raw query in createCommand() function. Here i used $search variable as you used in your sub query
i have a sql query like this and i want to convert it to laravel how i can do it?
i have try it, but i confusing on wherein and join
sql query
SELECT MIN(StartFrom) as StartFrom,MAX(EndTo) as EndTo from appointmentsettings
WHERE day=1
and PersonID IN (
SELECT p.id
FROM users p
JOIN appointmentsettings aps ON p.id = aps.PersonID
WHERE p.active=1 AND aps.CompanyID = 1 OR aps.PersonID IN(
SELECT cps.user_id
from companypersonstructs cps
WHERE cps.CompanyID =1
) group by aps.PersonID
)
and active=1
here what i try
Appointmentsetting::select('StartFrom', 'EndTo')
->min('StartFrom')
->max('EndTo')
->where(['Day'=>$day, 'Active'=>1])
->whereIn('PersonID', function ($query) use ($id) {
$query->select('p.id')
->from('users as p')
$query->join('appointmentsettings as aps', 'p.id', '=', '')
->where(["user_id" => $id, 'Active' => 1])->get();
})->orderBy('id')->get();
Appointmentsetting::select('StartFrom', 'EndTo')
->min('StartFrom')
->max('EndTo')
->where(['Day'=>$day, 'Active'=>1])
->whereIn('PersonID', function ($query) use ($id) {
$query->select('p.id')
->from('users as p')
->join('appointmentsettings as aps', 'p.id', '=', '')
->where(["user_id" => $id, 'Active' => 1]);
})->orderBy('id')->get();
You have an error in your join inside the function. Try the above code.
Also you must use get() only at the end of the query and not inside the function itself.
DB Query way
DB::table('appointmentsettings')->join('users','p.id','=','')
->select(DB::raw('MIN(StartFrom) as StartFrom','Max(EndTo) as EndTo'))
->where([['user_id',$id],['Active','1']])
->groupBy('appointmentsettings.PersonID)
->orderBy('id','ASC')
->get();
I want to join multiple tables, as in my picture:
Here is my code:
$this->db->select('
pt2.turl as `p_img`,
p.title as `p_title`,
p.text as `p_text`,
p.create as `p_date`,
pt3.turl as `c_img`,
u.name as `c_name`,
c.text as `c_text`,
c.create as `c_date`
');
$this->db->from('posts as p, users as u, photos as pt2, photos as pt3');
$this->db->join('comments as c', 'p.id=c.pid AND u.id=c.uid');
$this->db->join('posts as p2', 'p2.pid=pt2.id', 'rihgt');
$this->db->join('users as u2', 'u2.photoid=pt3.id', 'right');
$this->db->order_by('c.id', 'DESC');
$this->db->limit('7');
$qry = $this->db->get();
return $qry->result();
If I understand you correctly, this is kind of what you're looking for. I haven't tried it out so it may not be exact, but you shouldn't need to make 2 table associations (pt2 and pt3) for the same table in the join. Just Include them in the select and join on the unique ID's
The "Left" is a join that is centered around you're left table so everything hangs off of that. Since you are joining the users table before the photo table, you should be able to join on its columns.
Hope this helps. Let me know if I missed something. :)
$select = array(
pt2.turl as `p_img`,
p.title as `p_title`,
p.text as `p_text`,
p.create as `p_date`,
pt2.turl as `c_img`,
u.name as `c_name`,
c.text as `c_text`,
c.create as `c_date`
);
//Set tables to variables. Just makes it easier for me
$postsTable = "posts as p"; //This will be your left table.
$userTable = "Users as u";
$commentsTable = "comments as c";
$photosTable = "photos as pt2";
$this
->db
->select($select)
->from($postsTable)
->join($userTable, "p.uid = u.id", "left")
->join($commentsTable, "p.cid = c.id", "left")
->join($photosTable, "u.photoid = pt2.id", "left")
->get();
I solved this problem myself
It would be like this:
$select= array (
//'*',
'pt.turl p_img',
'p.title p_title',
'p.text p_text',
'p.create p_date',
'pt2.turl c_img',
'c.text c_text',
'u.name c_name',
'c.create c_date'
);
$from = array (
'posts p'
);
$qry = $this
->db
->select($select)
->from($from)
->join('comments c', 'c.pid=p.id')
->join('photos pt', 'pt.id=p.pid')
->join('users u', 'u.id=c.uid')
->join('photos pt2', 'u.photoid=pt2.id')
->order_by('c.create', 'DESC')
->limit('7')
->get();
return $qry->result();
Am currently having this issue where my database query takes too long to execute and sometimes ends up failing with an error: Maximum Execution Time Exceeded... Am trying to select data from different tables that aren't directly related to each other, i.e One table is related to a table which is related to another table and so on, Some of this tables have over a thousand records, I have a feeling the structure of the different tables contributes to this headache, but I haven't been able to figure out how to reduce this execution time. Am using a CodeIgniter model where i created a function with the following sql query:
/**
* Get payment history based on search term
* #param string $search
* #param int $limt => default is 10
* #return mixed
**/
public function get_search_history($usertin, $search, $limit, $offset){
$this->db->select("
rv.name AS 'Revenue Name',rv.code AS 'Rev. Code',
m.name AS 'MDA',m.sector AS 'Sector', b.code AS 'Bank Code',
b.name AS 'Bank',p.amount AS 'Amount',p.channel AS 'Payment Channel',
p.date AS 'Payment Date',p.platform AS 'Platform',p.ref AS 'Reference',
t.tin AS 'TIN',t.active AS 'Is Active?',r.ref AS 'Receipt Reference'
");
$this->db->from('revenue AS rv');
$this->db->join('mda AS m', 'm.id = rv.mda_id', 'inner');
$this->db->join('payment AS p', 'p.revenue_id = rv.id', 'inner');
$this->db->join('bank AS b', 'b.id = p.bank_id', 'inner');
$this->db->join('tin AS t', 't.id = p.tin_id', 'inner');
$this->db->join('receipt AS r', 'r.id = p.receipt', 'inner');
$this->db->where('t.tin', $usertin);
$this->db->like('rv.code', $search);
$this->db->or_like('rv.name', $search);
$this->db->or_like('m.name', $search);
$this->db->group_by('t.id');
$this->db->order_by('p.date', 'ASC');
$this->db->limit($limit, $offset);
$query = $this->db->get();
return ( ( $query->num_rows() > 0 ) ? $query->result_array() : 0 );
}
The query is supposed to retrieve a user's payment history based on a particular search term or keyword!
It's easier to see from the above query what I meant when I said "...One table is related to a table which is related to another table..." I Just can't figure out a better way of doing this. Can anyone help me out? It's given me serious headaches the past couple of days!
This is the output of the query:
SELECT rv.name AS 'Revenue Name', rv.code AS 'Rev. Code', m.name AS
'MDA', m.sector AS 'Sector', b.code AS 'Bank Code', b.name AS 'Bank',
p.amount AS 'Amount', p.channel AS 'Payment Channel', p.date AS 'Payment
Date', p.platform AS 'Platform', p.ref AS 'Reference', t.tin AS 'TIN',
t.active AS 'Is Active?', r.ref AS 'Receipt Reference'
FROM `revenue` AS `rv`
INNER JOIN `mda` AS `m` ON `m`.`id` = `rv`.`mda_id`
INNER JOIN `payment` AS `p` ON `p`.`revenue_id` = `rv`.`id`
INNER JOIN `bank` AS `b` ON `b`.`id` = `p`.`bank_id`
INNER JOIN `tin` AS `t` ON `t`.`id` = `p`.`tin_id`
INNER JOIN `receipt` AS `r` ON `r`.`id` = `p`.`receipt`
WHERE `t`.`tin` = '1904260529-0001'
AND `rv`.`code` LIKE '%With%' ESCAPE '!'
OR `rv`.`name` LIKE '%With%' ESCAPE '!'
OR `m`.`name` LIKE '%With%' ESCAPE '!'
GROUP BY `t`.`id`
ORDER BY `p`.`date` ASC
LIMIT 3, 20
If you have this much tables to join frequently, there are 2 possible ways I can suggest.
1. Use CodeIgniter's feature Query Caching
You just have to enable it from database.php and have to give it a folder path where all cached queries will lie.
Then you can create hook or something to delete and regenerate that cached queries on particular condition.
2. Create View in MySQL
You can create View in MySQL which will be much faster. It can be done easily right from PHPMyAdmin even.
Hope this helps.
p.s. Try indexing proper columns.
Simple thumb rule is As more conditions in WHERE clause, As lower query will be
I have two tables project and workload. I want show user in some project that added in Workload, and anothers member in this project (I called Team Member of that Project), too.
My idea is join 2 tables project and workload with user_id condition to take projects of user have user_id, then, from that will join with workload table again to take data from project of user have that user_id and user_id of team member will have that projects.
That my code in WorkloadSearch.php
public function searchWorkloadofUser($params) {
$user_id = Yii::$app->user->id;
$query = Workload::find()
->select(['workload.project_id', 'workload.commit_time', 'project.project_name', 'workload.from_date', 'workload.to_date', 'workload.workload_type', 'workload.comment'])
->join('INNER JOIN', 'project', 'workload.project_id=project.id')
->where('workload.user_id = '.$user_id)->orderBy('project.project_name ASC')->distinct();
$query->join('INNER JOIN','workload', 'project.id = workload.project_id')->distinct();
}
I don't understand why appeared error:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'workload'
The SQL being executed was: SELECT COUNT(*) FROM (SELECT DISTINCT `workload`.`project_id`, `workload`.`commit_time`, `project`.`project_name`, `workload`.`from_date`, `workload`.`to_date`, `workload`.`workload_type`, `workload`.`comment` FROM `workload` INNER JOIN `project` ON workload.project_id=project.id INNER JOIN `workload` ON project.id = workload.project_id WHERE workload.user_id = 20) `c`
like the others said: You need an alias. Your error messages tells you:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'workload'
This is beacause you joined your table worload to your workload table:
$query = Workload::find() //your `workload` table
->select([
....
])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id = '.$user_id)
->orderBy('p.project_name ASC')
->distinct();
$query->join('INNER JOIN','workload', 'project.id = workload.project_id') //join the `workload` table to the `workload` table
->distinct();
When you want to join a table to itself, you have to define an alias at least for the joining table.
I would recommend you to quote the tablenames and columns whis is described in the Yii2 guide here and do not concat strings but bind params like it's described here and here. This code should work for you (not tested):
$query = Workload::find() //your `workload` table
->select([
'{{workload}}.[[project_id]]', //quoting tablenames and columns
'{{%workload}}.[[commit_time]]', //add '%' when you're using table prefix
...
])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id' = :user_id, [':user_id' => $user_id]) //You should bind params when use string format
//or use hash format
//->where(['workload.user_id' => $user_id])
...
$query->join('INNER JOIN','workload w2', 'project.id = w2.project_id') //Use the alias `w2` to join the `workload` table to the `workload` table
->distinct();
You need to give the user table an alias the second time you join to it
e.g.
SELECT workload.project_id, workload.commit_time, p.project_name, ...
FROM workload
LEFT JOIN project p ON p.id = workload.project_id
WHERE workload.user_id = '1'
Your solution should be (untested):
public function searchWorkloadofUser($params)
{
$user_id = Yii::$app->user->id;
$query = Workload::find()
->select(['workload.project_id', 'workload.commit_time', 'p.project_name', 'workload.from_date', 'workload.to_date', 'workload.workload_type', 'workload.comment'])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id = '.$user_id)->orderBy('p.project_name ASC')->distinct();
...