How to Group by all 12 months in MySQL? - mysql
I am using cakephp 1.3. I have date field in incomes table. I am trying to get total income per month in a loop. The following is my query.
$income_and_hst = $Income->find('all', array(
'fields' => array('SUM(Income.amount) as income',
'SUM(Income.hst_amount) as hst',
'MONTH(date) as month'),
'conditions' => array(
'Income.income_account_id' => array(1,2,3,4),
'Income.user_id' => $this->Auth->user('id'),
'Income.account_id' => $this->Session->read('Account.default_account'),
'Income.date >' => $starting_date,
'Income.date <' => $ending_date,
),
'group' => 'MONTH(date)',
)
);
This gives me 5 months of income. Because the income were from 5 months. I need to show all 12 months even there is no income in other months. If there is no income i want 0 for that month.
Could someone give me a direction please?
Thank you.
My guess is that you cannot do that using that interface. You either need to dive into raw SQL (and a cross join), or add the missing months in the surrounding php code. I suggest the latter something like this should work (pseudocode, i don't remember php syntax):
for ($row in $income_and_hst) {
$income_and_hst_all[$row['month']] = $row
}
for ($month = 1;$month <= 12; $month++) {
if ($income_and_hst_all[$month] == nil) {
$income_and_hst_all[$month] = Array (
'income' => 0,
'hst' => 0,
'month' => $month
)
}
}
Related
Codeigniter: How to update an amount that will not affect a specific columns
Hi guys I have a problem in my query in model, I'll show you the code before I explain it. for($x = 1; $x <= count($this->input->post('subparticulars')); $x++) { $feetype = $this->input->post('subparticulars')[$x]; $student = $this->input->post('substudentid'); $schoolyear = $this->input->post('subschoolyeardata'); $month = $this->input->post('month'); $payment = $this->input->post('subpaymentamount')[$x]; $this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE); $this->db->where(array('feetype_id !=' => 2, 'feetype_id !=' => 3, 'feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear, 'month_id' => $month)); $status3 = $this->db->update('tbl_statement'); } Here I have an add dynamic add row function which has contains the amounts and particulars of multiple payment in subparticulars and subpayments, I'm running a query that will minus my payments in my statement_amounts, as you can see in the $this->db->set. Now, I have a problem with my where clause, if you will try to understand my where clause this is the conditions. I want to update all my fees except the one that has the feetype_id: 2 and 3, but the other feetype_id will be updated, How can I achieve this. When I'm running the code it still subtracts the fees that have feetype_id of 2 and 3.
Here's the correct answer for($x = 1; $x <= count($this->input->post('subparticulars')); $x++) { $feetype = $this->input->post('subparticulars')[$x]; $student = $this->input->post('substudentid'); $schoolyear = $this->input->post('subschoolyeardata'); $month = $this->input->post('month'); $payment = $this->input->post('subpaymentamount')[$x]; if ($feetype == 2 OR $feetype == 3) { $this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE); $this->db->where(array('feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear)); $status3 = $this->db->update('tbl_statement'); } else { $this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE); $this->db->where(array('feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear, 'month_id' => $month)); $status3 = $this->db->update('tbl_statement'); } }
How to code a complex array of hashes in Perl?
Here is a task that's puzzling me for quite a while now: Regularly, we get exam results of our students as a .csv file. The header has some meta data such as ID, gender, date of birth, status, exam room, seat number, exam version, and the score for 60 questions (0.0 0.5 1.0 points if the answer is wrong, half-correct, or correct). There are 6 versions (A - F) of the exam differing only by the order of the 60 questions. The information is stored for statistical evaluation which requires the correct alignment according to the exam master (a .txt file with 7 columns for version A-F and the correct answer in the 7th column). I tried to accommodate the .csv file as an array of hashes to generate a different .csv or tabbed .txt file in which all exam results appear in a unified order for later statistical evaluation. Example: header -- ID,gender,birthdate,order,room,seat,version,points,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 277710814533,f,01/02/1993,m,sr_3,A11,A, 1,1,1,1,0,1,1,1,.5,1,1,1,0,1,.5,1,1,1,0,1,.5,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,.5,1,1,1,1,.5,0,1,1,1,0,1,1,1,1,1,0,1,1,1,.5,1,1,1 755310765962,f,31/07/1992 00:00,v,aula,C11,C,1,.5,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,.5,1,0,.5,1,0,1,.5,0,.5,0,1,0,0,.5,1,1,0,.5,1,1,.5,.5,1,.5,.5,1,1,1,.5,.5 394610513538,m,20/10/1992 00:00,m,sr_3,E13,E,1,1,0,.5,1,1,1,1,1,1,1,.5,1,1,.5,.5,1,1,1,.5,.5,1,1,1,1,0,0,.5,1,1,.5,.5,.5,.5,0,1,0,.5,0,0,1,0,1,.5,0,1,0,0,.5,1,0,1,1,0,.5,.5,.5,.5,.5,.5 The code generates hash keys according to the following scheme: while ( <FH> ) { chomp ; if ( /^\d\d\d/) { ( $id , $gender , $birthday , $status , $room , $seat , $version , #points ) = split ( /,/ , $_ ) ; $student = { 'id' => $id , 'gender' => $gender , 'birthday' => $birthday , 'position' => $position , 'room' => $room , 'seat' => $seat , 'version' => $version , 'points' => #points } ; push ( #candidates , $student ) ; } } ; close FH ; print "Number of candidates processed: " . ( $#candidates + 1 ) . "\n" ; The compiler throws a warning for each record, e.g. "Odd number of elements in anonymous hash at /Documents//testAoH.pl line 38, line 16." but the script is executed. The script prints the correct number of processed records, but when I try to retrieve a specific record I only get the scalar values and the #points array yields only one (the first?) result as if it were destroyed. A data dumper output further shows that something must be internally wrong with this code. Data Dumper e.g. 755310765962 $VAR1 = \{ '0' => '0', 'gender' => 'f', 'id' => '755310765962', 'points' => '1', 'room' => 'aula', '.5' => undef, '1' => '.5', 'birthday' => '31/07/1992', 'seat' => 'A11', 'version' => 'A', 'status' => 'v' }; Any clues?
Use \#points. #points expands in the hash constructor to generate: 'Points' => $points[0], $points[1] => $points[2], ...
CakePhp Containable too many queries
I'm using CakePHP 2.5.2 and having a bit of trouble searching for data efficiently. In my application I've 3 tables, teams, players, skills... In teams there are 80 records, players 2400 records, skills 2400 records... I want to calculate the average skill of a team... //Team model public $actsAs = array('Containable'); public $hasMany = array('Player'); //Player model public $actsAs = array('Containable'); public $hasOne = array('Skill'); public $belongsTo = array('Team'); //Skill model public $actsAs = array('Containable'); public $belongsTo = array('Player'); My research is: $team = $this->Team->find('all', array( 'contain' => array( 'Player' => array( 'Skill' ) ), )); $this->set('team', $team); that gives the expected result: Array ( [0] => Array ( [Team] => Array ( [id] => 1 [name] => my_team_name ) [Player] => Array ( [0] => Array ( [id] => 000000419 [name] => Name [surname] => Surname [age] => 21 [team_id] => 1 [Team_id] => 1 [Skill] => Array ( [id] => 20 [player_id] => 000000419 [skill] => 599 ) ), ecc..... This structure use at least 1680 queries... that are too much for me... I've tried an other way, that involve just one query, returns a bad data structure but all the information that i need (also redundant). unfortunately follow this way i can not iterate in View to display what i need. $player = $this->Team->Player->find('all', array( 'contains' => array( 'Skill', ), that returns Array ( [0] => Array ( [Player] => Array ( [id] => 000000400 [nome] => my_player_name [cognome] => my_player_surname [nation_id] => 380 [age] => 29 [team_id] => 2 ) [Team] => Array ( [id] => 2 [nome] => my_team_name ) [Skill] => Array ( [id] => 1 [player_id] => 000000400 [average] => 632 ) ) ecc. Is there a way to iterate in VIEV to get the average skill of every team? Any other solutions? Thanks!
You can use my plugin to solve this issue if you can upgrade CakePHP to 2.6 or later. The plugin has a high compatibility with ContainableBehavior, but generates better queries. I think that the find operation will execute only 2 queries then. I would be happy if you try it. https://github.com/chinpei215/cakephp-eager-loader Usage 1. Enable EagerLoader plugin // In your model $actsAs = ['EagerLoader.EagerLoader']; If you are afraid that loading my plugin breaks something somewhere, you can also enable it on the fly. // On the fly $this->Team->Behaviors->load('EagerLoader.EagerLoader'); 2. Execute the same find operation $this->Team->find('all', ['contain' => ['Player' => ['Skill']]]); 3. See the query log You will see the query log such as the following: SELECT ... FROM teams AS Team WHERE 1 = 1; SELECT ... FROM players AS Player LEFT JOIN skills AS Skill ON Player.id = Skill.player_id WHERE Player.id IN ( ... );
if you feeling that query searching so many tables (ie, models) then you can unbind those model, before performing search with find() if you want to fetch some particular column of a table, then remove others column by selecting "fields" in find().
Cakephp find('list') with summarized data returns nulls
I have the following query in a Cakephp 2.4 model: $scores = $this->WorkInfo->find('list', array( 'conditions' => array('WorkInfo.work_id' => $work_ids), 'fields' => array('WorkInfo.date', 'SUM(WorkInfo.score)'), 'group' => array('WorkInfo.date') )); Which generates the following query: SELECT `WorkInfo`.`date`, SUM(`WorkInfo`.`score`) FROM `home`.`work_infos` AS `WorkInfo` WHERE `WorkInfo`.`work_id` IN (4, 7, 8, 12, 9, 11, 13, 10, 14, 6, 5) GROUP BY `WorkInfo`.`date` The result I get in my application is: '2014-03-24' => null '2014-03-25' => null '2014-03-26' => null '2014-03-27' => null '2014-03-28' => null '2014-03-31' => null While the result I get from pasting this very query in the mysql console is: '2014-03-24' => 0 '2014-03-25' => 36 '2014-03-26' => 0 '2014-03-27' => 164 '2014-03-28' => 0 '2014-03-31' => 0 What is going on here? It is supposed that same queries output same results, isn't it? I have read something about creating virtual fields for this, but I do not want to overkill, it should be possible to perform a simple aggregation query through Cakephp using the find function. Thanks!
Try this $scores = $this->WorkInfo->find('all', array( 'conditions' => array('work_id' => $work_ids), 'fields' => array('date', 'SUM(score) AS score'), 'group' => array('date') )); then with Set::combine you can format your array cakephp find list $scores = Set::combine($scores, '{n}.WorkInfo.date', '{n}.0.score'); prints=> '2014-03-24' => 0 '2014-03-25' => 36 '2014-03-26' => 0 '2014-03-27' => 164 '2014-03-28' => 0 '2014-03-31' => 0
Ok, sadly, I think what you want to do can't be done as you want to do it. Let's see, you use the find('list') method, so that's here in the API. Code looks normal, and as you said, query is ok, returns everything you want. Problem is in line 2883 return Hash::combine($results, $query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']); That line organizes the returned array after the query is done. And seeing the doc for that function, we have Creates an associative array using a $keyPath as the path to build its keys, and optionally $valuePath as path to get the values. If $valuePath is not specified, or doesn’t match anything, values will be initialized to null. Which is what happens to you. Now, debugging, the query result before applying the Hash::combine function is something like this Array ( [0] => Array ( [WorkInfo] => Array ( [date] => 2013-04-01 ) [0] => Array ( [SUM(`WorkInfo`.`score`)] => 24 ) ) ) so you see, you get the results. And the respective Hash::combine Array ( [groupPath] => [valuePath] => {n}.SUM(WorkInfo.score) [keyPath] => {n}.WorkInfo.date ) which probably causes problem with the dot inside the parenthesis. And the combine function doesn't find the valuePath, and you get null, and you get sad. If you change your query to 'SUM(WorkInfo.score) AS score' (leaving everything as is), you have almost the same problem with valuePath Array ( [groupPath] => [valuePath] => {n}.SUM(WorkInfo.score) as score [keyPath] => {n}.WorkInfo.date ) //respective result array Array ( [0] => Array ( [WorkInfo] => Array ( [date] => 2013-04-01 ) [0] => Array ( [score] => 24 ) ) ) You might think that doing 'SUM(score) AS score' (without the dot) will solve it, but the code of find('list') adds the alias if it doesn't find a dot (in line 2865). So... I guess what I'm saying is: do a virtual field, or listen to Isaac Rajaei, or create a custom find function. But with find('list') and SUM() you won't have luck :(
WordPress get specific posts in arbitrary order
Right now, I'm doing: $posts = get_posts(array('post_type' => 'page', 'post__in' => array(1, 3, 2, 9, 7))); and am having two issues: Post 3 is of 'post_type' => 'post', so it doesn't get selected, but I want it! If I leave out 'post_type' => 'page', then only post 3 is selected (because it must assume 'post_type' => 'post'.). I want to be able to order the posts arbitrarily by their ids. If I knew how to use MySQL, I could do: SELECT * FROM wp_posts WHERE ID IN (1, 3, 2, 9, 7) ORDER BY FIND_IN_SET(ID, '1,3,2,9,7'); But, how should I do this with WordPress?
First fetch all posts arbitrarily by their ids and then loop through all the posts You can do in this way:- $posts=$wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE ID IN (1, 3, 2, 9, 7) ORDER BY FIND_IN_SET(ID, '1,3,2,9,7')"); $count=count($posts); for ($counter=0 ; $counter < $count; $counter++) { $post=get_post( $posts[$counter]->ID, $output ); //do your stuffs with posts } Hope this helps
Kawauso on the #wordpress IRC channel informed me that "post_type takes an array of values." From that, I found that the following also selects post 3: So, I did the following: $post_ids = array(1 => 0, 3 => 1, 2 => 2, 9 => 3, 7 => 4); $posts = get_posts(array('post_type' => array('post', 'page'), 'post__in' => array_keys($post_ids))); $ordered_posts = array(0,0,0,0,0); // size of five; keeps order foreach ($posts as $p) { setup_postdata($p); $ordered_posts[$post_ids[$p->ID]] = array( 'permalink' => get_permalink($p->ID), 'title' => $p->post_title, 'excerpt' => get_the_excerpt(), 'date' => date('F j, Y', strtotime($p->post_date))); }
According to this thread, you can use this code and then use the classic WordPress loop: $args = array( 'post_type'=>'page', 'orderby'=>'menu_order', 'order'=>'ASC' ); query_posts($args);