How to write MySQL query in CakePHP format? - mysql

i have faced in a problem.
Can you please write this query in cakephp format
Table
id from_id to_id is_active message
--- ------- ----- --------- -------
1 1 8 1 Hello
2 8 1 1 Yes
3 1 8 1 How are you?
4 1 8 1 Are you with me?
Code :
<?php
$qry = mysql_query("SELECT * FROM messages WHERE (from_id='8' OR to_id='1') AND (from_id='1' OR to_id='8') AND id_active='1'"));
$res = mysql_fetch_array($qry);
?>
Edit
I have written but getting null value
my code:
$condition = array('OR'=>array('Message.from_id'=>1,'Message.to_id'=>8),'OR'=>array('Message.from_id'=>8,'Message.to_id'=>1),'Message.is_active'=>1);
$message=$this->Message->find("all",array('conditions'=>$condition));
pr($message);
Output:
array
(
)

Hi if you would like to list the conversation try out this:
$this->Message->find('all' ,
array(
'conditions'=>array(
'AND'=>array(
'OR'=>array(
array('AND'=>array('from_id'=>1, 'to_id'=>'8')),
array('AND'=>array('from_id'=>8, 'to_id'=>'1'))
),
'is_active'=>1
)
)
)
);
The good query is:
SELECT Message.id, Message.from_id, Message.to_id, Message.is_active, Message.message FROM c23dev1.messagess AS Message WHERE ((((((from_id = 1) AND (to_id = 8))) OR (((from_id = 8) AND (to_id = 1))))) AND (is_active = '1'))

I can recommend using Dogmatic69's converter. That gave this result for your query:
'conditions' => array(
array(
'or' => array(
'from_id' => '8',
'to_id' => '1',
),
),
'id_active' => '1',
),
I'm not sure what your original SQL query is actually trying to return, but if you want all messages between user 7 and user 8, your query should be something like:
SELECT *
FROM messages
WHERE ((from_id='7' AND to_id='8') OR (from_id='8' AND to_id='7'))
AND is_active='1';
Here's a SQLFiddle example.

Related

How to perform GroupBy of a GroupBy in laravel?

I have a reports table which looks like something as follows:
Reports is monthly reports of users putting their efforts. It's many to many relationship table.
id
user_id
project_id
total_effort
created_at
1
5
232
40
2023-01-23
I want to get all users with their contributions projects-wise so that I can create an excel something like this.
I am able to group users by group and get their collective data, but unable to group by project id as well.
So far here is my query
$data = Report::select('user_id')
->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
->groupBy('user_id')->with('userDetail:id,first_name,last_name')->get();
And this query return
[0] => Array
(
[user_id] => 2
[total] => 500
[new_date] => Dec,2022
[user_detail] => Array
(
[id] => 2
[first_name] => Hermione
[last_name] => Granger
)
)
But what I am actually looking for is something like this:
[0] => Array
(
[user_id] => 2
[total] => 500
[new_date] => Dec,2022
[projects]=>Array(
[0]=>Array(
[project_id]=>1,
[total]=>30,
[project_detail]=>Array(
[id]=>1
[name]=>Project 1
)
)
[1]=>Array(
[project_id]=>41,
[total]=>30,
[project_detail]=>Array(
[id]=>41
[name]=>Project 41
)
)
[2]=>Array(
[project_id]=>32,
[total]=>30,
[project_detail]=>Array(
[id]=>32
[name]=>Project 32
)
)
)
[user_detail] => Array
(
[id] => 2
[first_name] => Hermione
[last_name] => Granger
)
)
So that I can loop the data and plot them in excel.
How can this be done? Even if it is just a Raw MySQL query how to do Groupby inside a groupBy?
Some reference that I checked but without any help
sql group by sub group
Mysql Nested query and GROUP BY
using group function inside group function
You can use with() method to load the relation with groupby clause
$data = Report::select('user_id', 'project_id')
->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
->groupBy('user_id')
->groupBy('project_id')
->with('userDetail:id,first_name,last_name')
->with('projectDetail:id,name')
->get();
I would query the active projects within the reporting period and then use that to build up the main query with conditional aggregation (pivot) -
// get list of projects within reporting period
$projects = DB::table('projects p')
->join('reports r', 'p.id', '=', 'r.project_id')
->select('p.id', 'p.name')
->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
->groupBy('p.id')
->get();
// build conditional aggregates
$columns = ['CONCAT(u.first_name, \' \', u.last_name) AS username'];
foreach ($projects as $project) {
$columns[] = "SUM(IF(r.project_id = {$project->id}, total_effort, 0)) AS project_{$project->id}";
}
// Add total column
$columns[] = 'SUM(total_effort) AS total';
$report = DB::table('reports r')
->join('users u', 'r.user_id', '=', 'u.id')
->selectRaw(implode(',', $columns))
->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
->groupBy('r.user_id')
->get();
The idea is to build and execute a query which looks something like this -
SELECT
CONCAT(u.first_name, ' ', u.last_name) AS username,
SUM(IF(r.project_id = 232, total_effort, 0)) AS project_232,
SUM(IF(r.project_id = 233, total_effort, 0)) AS project_233,
SUM(IF(r.project_id = 234, total_effort, 0)) AS project_234,
SUM(total_effort) AS total
FROM reports r
JOIN users u ON r.user_id = u.id
WHERE r.created_at BETWEEN '2023-01-01' AND '2023-01-31'
GROUP BY r.user_id

CakePHP Database Query Count(Case When)

I'm using CakePHP and cannot seem to translate this SQL query I did on the workbench. It's exactly what I want to do but I cannot seem to make it work.
This is my query on MySQL:
select
docs.id, docs.schoolId, schools.name, docs.datesubmitted, docs.status,
uploads.iddocs,
COUNT(*),
COUNT(case uploads.staff_checked when 1 then 1 else null end)
FROM
docs as docs, schools as schools,
uploads as uploads
where
docs.schoolId = schools.schoolId AND
docs.id = uploads.iddocs AND
docs.status ="Submitted"
group by
docs.id;
What I need to do is combine three tables: Docs, Schools, and Uploads.
The two counts: COUNT(case when) and COUNT(*) indicate the number of documents reviewed (COUNT(case when)) and total documents needed to be reviewed (COUNT(*)).
So far MySQL is showing what I need. Can someone figure out how to do it in Cake?
Try the following query
$this->virtualFields = array(
'count_case_uploads_staff_checked_when_1_then_1_else_null_end' => 'COUNT(case uploads.staff_checked when 1 then 1 else null end)',
'count' => 'COUNT(*)',
);
$options = array(
'fields' => array(
'Doc.id',
'Doc.schoolId',
'schools.name',
'Doc.datesubmitted',
'Doc.status',
'uploads.iddocs',
'Doc.count_case_uploads_staff_checked_when_1_then_1_else_null_end',
'Doc.count',
),
'joins' => array(
array(
),
),
'conditions' => array(
'Doc.schoolId = schools.schoolId',
'Doc.id = uploads.iddocs',
'Doc.status' => 'Submitted',
),
'group' => array(
'Doc.id',
),
);
$data = $this->find('all', $options);

Cakephp find joining two columns

I have a BD that contains people with day and month fields, like so:
person1 (day = 5; month = 3)
person2 (day = 2; month = 12)
I have to perform a find between 2 dates, for example, I need all people between 01/03 and 01/06 (day/month) but I don't know how to perform that.
I tried using separate conditions, like this:
$conditions['People.day >='] = dayA;
$conditions['People.month >='] = monthA;
$conditions['People.day <='] = dayB;
$conditions['People.month <='] = monthB;
But, that's not correct because it finds day and month, I mean, it finds People between monthA and monthB and People between dayA and dayB, instead, what I need is people between dayA/monthA and dayB/monthB
I suppose I must do some kind of a JOIN, but I'm lost here, I looked some information but I don't know where to start.
updated info:
ok, I'm using this
Array
(
[People.month_day BETWEEN ? AND ?] => Array
(
[0] => 01/02
[1] => 28/02
)
)
but I get people like this:
1/1
2/1
10/1
11/1
12/1
13/1
20/1
21/1
1/2
what's wrong? do you need more code? I'm using this to retrieve results:
A paginate:
public $paginate = array('People'=>array(
'limit' => 16,
'order' => 'People.month, People.day ASC'
));
In your People model
public $virtualFields = array(
'month_day' => 'CONCAT(People.month, "-", People.day)'
// 'month_day' => 'CONCAT(People.day, "/", People.month)'
);
then add in your controller
$options = array(
'conditions' => array(
'Post.month_day BETWEEN ? AND ?' => array('01-03','01-06')
// 'Post.month_day BETWEEN ? AND ?' => array('03/01','06/01')
)
);
$posts = $this->Post->find('all',$options);
It would be best to alter your table. Use DATE field and your SQL query would be:
SELECT *
FROM dbname.People
WHERE People.date BETWEEN '1999-03-01' AND '1999-06-01';

Message list: order by and group by query on cakephp and mysql

I want to change my message list page/inbox. Currently it shows all the messages from the DB like if someone send me a message 3 times, it will all appear in my inbox. Now i want to make it simple like every sender will appear only once in the list and will show the latest message that he/she sent.
This is my code in cakephp:
$this->paginate = array(
'Message'=> array(
'conditions'=>array('Message.recipient_id'=>$this->user_id),
'group' => array('Message.sender_id'),
'order'=>'message_sent_date DESC',
'limit'=> 20,
)
);
The problem with this code is it shows the oldest message content. I think it's because group by always first before order by.
I was able to do it on mysql query but i don't know how to make it on cakephp.
Here's my query:
SELECT *
FROM(
SELECT *
FROM messages WHERE recipient_id = 114
ORDER BY message_viewed_date DESC
) AS messages
GROUP BY sender_id
ORDER BY message_viewed_date DESC
Please help me with this.. Thanks.
This should do the trick (make sure your models are set up correctly):
$results = $this->Message->find('all', array(
'conditions' => array(
'recipient_id' => 114
),
'group' => 'sender_id',
'order' => 'message_viewed_date DESC'
));
No need for the sub query there, it's not doing anything fancy. The manual will help you with queries like this.
I've solve this problem using the Model::query() http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-query
here's my code:
$messages = $this->Message->query("SELECT id FROM(SELECT * FROM messages WHERE recepient_id = ". $this->user_id ." ORDER BY message_sent_date DESC) AS Message GROUP BY sender_id ORDER BY message_sent_date DESC");
for($i=0; $i<count($messages); $i++){
$message_id[$i] = $messages[$i]['Message']['id'];
}
$this->paginate = array(
'Message'=> array(
'conditions'=>array('Message.id' => $message_id, 'Message.recepient_id'=>$this->user_id, 'Message.hidden_on_to'=>false),
'limit'=>20,
'order'=>array('Message.message_sent_date' => 'DESC'),
'recursive'=>0,
'fields'=>array('Message.id', 'Message.message_content', 'Message.message_sent_date', 'Message.message_viewed_date', 'Sender.id', 'Sender.username')
)
);

Pagination using joining multiple models

Each exam has one syllabus, each syllabus has one exam. So, I did this in the Exam model:
public $hasOne = 'Syllabuses'; //table: syllabuses, model: Syllabuses
From UsersController I did this:
public $uses = array('Setting', 'Exam', 'Syllabuses');
And in a method in UsersController I wanted to call paginate:
$options = array(
'fields' => array('Exam.id', 'Exam.name', 'Syllabuses.id', 'Syllabuses.name', 'Syllabuses.syllabus', 'Syllabuses.last_updated'),
'joins' => array(
'table' => 'syllabuses',
'conditions' => array('Exam.id = Syllabuses.exam_id')
)
);
$this->paginate = $options;
$this->set('syllabuses', $this->Paginator->paginate('Syllabuses'));
exams table:
---+------+
id | name |
---+------+
and syllabuses table:
---+---------+------+----------+--------------+
id | exam_id | name | syllabus | last_updated |
---+---------+------+----------+--------------+
So, I got some error. Like this:
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'syllabuses Array LEFT JOIN oes.syllabuses AS Syllabuses ON (Syllabuses.`' at line 1
And my SQL that CakePHP prepared is:
SELECT `Exam`.`id`, `Exam`.`name`, `Syllabuses`.`id`, `Syllabuses`.`name`, `Syllabuses`.`syllabus`, `Syllabuses`.`last_updated`
FROM `oes`.`exams` AS `Exam` syllabuses Array
LEFT JOIN `oes`.`syllabuses` AS `Syllabuses` ON (`Syllabuses`.`exam_id` = `Exam`.`id`)
WHERE 1 = 1 LIMIT 20
But what I want is something like the query bellow. I have tested it in mysql:
SELECT `Exam`.`id` AS eid, `Exam`.`name` AS ename, `Syllabuses`.`id` AS sid, `Syllabuses`.`name` AS sname, `Syllabuses`.`syllabus` , `Syllabuses`.`last_updated`
FROM `oes`.`syllabuses` AS `Syllabuses` , exams AS Exam
WHERE Exam.id = Syllabuses.exam_id
ORDER BY Exam.id
LIMIT 20
Now anybody please help me achieve this. What kind of change can make CakePHP to prepare query like that(what I've tasted) to make my Pagination done.
Ok, I think this can be helpful for many programmers. That's why I want to share what I did finally:
$options = array(
'fields' => array(
'Exam.id',
'Exam.name',
'Syllabuses.id',
'Syllabuses.name',
'Syllabuses.exam_id',
'Syllabuses.syllabus',
'Syllabuses.last_updated'
),
'recursive' => 0,
'conditions' => array('Exam.id = Syllabuses.exam_id'),
'limit' => 3
);
$this->paginate = $options;
$syllabuses = $this->Paginator->paginate('Exam');