Following is the Banking MySQL table structure:
id | name | type
1 | abc | xyz
2 | jkl | xyz
3 | efg | pql
Right now the records are displayed in the following format:
Array
(
[0] => Array
(
[Banking] => Array
(
[id] => 1
[name] => abc
[type] => xyz
)
)
[1] => Array
(
[Banking] => Array
(
[id] => 2
[name] => jkl
[type] => xyz
)
)
[2] => Array
(
[Banking] => Array
(
[id] => 3
[name] => efg
[type] => pql
)
)
)
I need to GroupBy fields according to type field and display all records. Following is the desired structure:
Array
(
[xyz] => Array
(
[0] => Array
(
[id] => 1
[name] => abc
)
[1] => Array
(
[id] => 2
[name] => jkl
)
)
[pql] => Array
(
[0] => Array
(
[id] => 2
[name] => efg
[type] => xyz
)
)
)
I tried Grouping it the following way but didn't work since GroupBy shows only one record per type.
$bankList = $this -> Banking -> find('all', array(
'order' => 'Banking.name asc',
'fields' => array(
'Banking.id',
'Banking.name',
'Banking.type'
),
'group' => array('Banking.type')
));
Though I achieved the result customizing $bankList:
foreach ($bankList as $b) {
if (!in_array($b['Banking']['type'], $type)) {
$type[] = $b['Banking']['type'];
}
$bList[$b['Banking']['type']][] = array(
'name' => $b['Banking']['name'],
'id' => $b['Banking']['id']
);
}
but wondering if its possible with a Query only?
I tried Grouping it the following way but didn't work since GroupBy
shows only one record per type.
You might want to learn SQL first, because this is the expected behaviour of GROUP BY, see What does group by do exactly ?
The resulting array structure you get is the standard CakePHP structure and has nothing at all to do with the SQL itself. It is just how CakePHP formats them.
Use the Model::afterFind() callback to modify the result as you need. Create a new method like transformResult() and pass your data through it in afterFind().
You can achieve the desired structure by manipulating data after you fetched it from a database. In CakePHP you can use a groupBy method:
$bankList = $this -> Banking -> find('all', array(
'order' => 'Banking.name asc',
'fields' => array(
'Banking.id',
'Banking.name',
'Banking.type'
)
)) -> groupBy('type');
Please note, that it has nothing to do with SQL queries! It is just a convenient way to do same data restructuring as your code.
Related
i'm using this class for accessing odoo through PHP XMLRPC.
Everything works fine almost. I can't search many2one fields just by placing the id of the referenced record. I guess there should be a special way to code the many2one id in the search.
EG: searching in product.supplierinfo by the product_tmpl_id using this code i get emtpy array returned:
$rpc->searchread(array(array("product_tmpl_id","=","3673")),"product.supplierinfo");
Searching for the record by id i get this result:
$rpc->read(array(1),"", "product.supplierinfo");
Array
(
[0] => Array
(
[create_uid] => Array
(
[0] => xxxxx
[1] => xxxxx xxxxx
)
[product_code] =>
[create_date] => 2016-06-22 11:08:00
[name] => Array
(
[0] => 1438
[1] => Provider one
)
[product_uom] => Array
(
[0] => 1
[1] => Unit(s)
)
[sequence] => 1
[product_name] =>
[__last_update] => 2016-06-22 11:42:28
[company_id] => Array
(
[0] => 1
[1] => Company Name
)
[write_uid] => Array
(
[0] => xxxx
[1] => xxxxxx xxxxx
)
[delay] => 1
[write_date] => 2016-06-22 11:42:28
[pricelist_ids] => Array
(
)
[display_name] => Provider One
[min_qty] => 0
[qty] => 0
[product_tmpl_id] => Array
(
[0] => 3673
[1] => Product Name
)
[id] => 1
)
)
How should i code the id of a many2one field?
Any help will be appreciated.
Finally i had the solution. As #czoellner suggested was a problem was the type of the ID was a string and must be an integer. So, this code worked fine.
$rpc->searchread(array(array("product_tmpl_id","=",3673)),"product.supplierinfo");
On the other hand must consider the issue between the id of the product.product and the id of the product.template because they are differents. The table product.supplierinfo uses the id of product.template instead product.product. That causes for searching through the table produc.supplierinfo is necessary to find first the product_tmpl_id of the product to refer to the product. So for finding a all the providers of a product:
#search it by id
$prod_odoo = $rpc->read(array(1),"product.product",array());
#every search returns a 2 dimension array
$prod_suppliers = $rpc->searchread(array(array("product_tmpl_id","=",(int)$prod_odoo[0]["product_tmpl_id"][0])),"product.supplierinfo");
Hope this helps.
I'm using CakePHP 2.3.8 and I'm trying to more efficiently join two tables. buildings and building_rental_rates
buildings
id | name | description | property_owner | building_type
1 Big Big Building 1 1
building_rental_rates
id | building_type | rate_name | rate
1 1 daily 150.00
2 1 hourly 15.00
I want to look up a building and select the different rental rates. The tables are joined on building_type. Here's the find statement I have
$buildings = $this->Building ->find('all',array(
'Building.property_owner' => '1',
'fields' => array('Building.*','BuildingRentalRate.*'),
'joins' => array(
array(
'table' => 'building_rental_rates',
'alias' => 'BuildingRentalRate',
'type' => 'inner',
'conditions' => array(
'Building.building_type = BuildingRentalRate.building_type'
)
)
)
));
Here is the result
Array
(
[0] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[id] => 1
[building_type] => 1
[rate_name] => daily
[rate] => 150.00
)
)
[1] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[id] => 2
[building_type] => 1
[rate_name] => hourly
[rate] => 15.00
)
)
)
While the data is found properly, it's a pain to traverse through it. Can I use a join statement to result in this output? Notice how the BuildingRentalRate is an array containing all entries of that table that share the same building_type
Array
(
[0] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[0] => Array
(
[id] => 1
[building_type] => 1
[rate_name] => daily
[rate] => 150.00
)
[1] => Array
(
[id] => 2
[building_type] => 1
[rate_name] => hourly
[rate] => 15.00
)
)
)
)
I know Cake can output results like this when using model associations, but I wasn't able to get my associations correct apparently because it kept on joining Building.id on BuildingRentalRate.building_type (it should be Building.building_type = BuildingRentalRate.building_type)
Even with my association like this...
//Building.php
public $hasMany = array('BuildingRentalRate' => array('foreignKey' => 'building_type'));
//BuildingRentalRate.php
public $belongsTo = array('Building' => array('foreignKey' => 'building_type'));
It would join Building.id on BuildingRentalRate.building_type despite specificying building_type in both models as the foreign key.
Can I do some kind of nested SQL query in the conditions or is there an easier way of doing this?
you should be able to avoid using joins if in BuildingRentalRate.php you set your relationship this way
$public belongsTo = array(
'Building' => array(
'foreignKey' => false,
'conditions' => array
(
'Building.building_type' => 'BuildingRentalRate.building_type'
)
)
);
Array
(
[Site] => Array
(
[id] => 1
[parent_id] => 0
[title] => test
[url] => http://www.test.com
[slug] => www_test_com
[keywords] => cpc,seo
[language_id] => 1
)
[SiteMeta] => Array
(
[0] => Array
(
[id] => 1
[site_id] => 1
[key] => pagerank
[value] => 5
[created] => 2010-08-03 00:00:00
)
)
)
By using cakephp, I debug my find('all') and returned me above array. I can sort Site field values by order value inside find function how I am able to order also with SiteMeta values
Any ideas?
Thanks
I'd do this in the Model as part of the association.
$hasMany = array('SiteMeta'=>array('order'=>array('SiteMeta.value'=>'asc')))
You won't have to repeat yourself anywhere then.
you can use a default query with a order condition like this:
$result = $this->Site->find('all', array(
'order'=>array('SiteMeta.value DESC' , 'Site.value DESC'),
'recursive'=>1));
Obviously you can put a condition inside the array to retrieve your right result
I would do it this way (as shown in the Docs)
$result = $this->Site
->find()
->contain([
'SiteMeta' => [
'sort' => ['SiteMeta.pagerank' => 'ASC']
]
]);
I have the models User, Post, Comment and Tag.
User creates Post.
Posts can have multiple Comment and Tag.
Each model has it's own table, so there are tables 'posts', 'comments' and 'tags'. Comments have a foreign key called 'post_id', while Tags have a many_to_many relation table called 'post_tags', in which there are two fields: 'post_id' and 'tag_id'.
I want to get a nested array like below:
Which MySQL queries should I run?
I suppose I need to alter the result with PHP to get my nested array. How?
Thanks a lot for your help :-)
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan#example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
[1] => Array
(
[id] => 2
[post_id] => 1
[author] => Sam
[email] => sam#example.net
[website] => http://example.net
[comment] => Second comment
[created] => 2008-05-18 00:00:00
)
)
[Tag] => Array
(
[0] => Array
(
[id] => 1
[name] => Awesome
)
[1] => Array
(
[id] => 2
[name] => Baking
)
)
)
[1] => Array
(
[Post] => Array
(...
You better of doing 3 queries.
first fetch post (, and left join the user if you need it), and store them like:
$list[$row['post_id']]['Post'] = $row;
then fetch all post-comments and store them as
$list[$row['post_id']]['Comment'][$row['comment_id']] = $row;
then fetch all post-tags
$list[$row['post_id']]['Tags'][$row['tag_id']] = $row;
that far more effective than trying to use a single query,
as a single query going to end up sending the same data multiple times
I am looking for an efficient way to combine results from a REST API with results from a query to a hosted MySQL database. I need the ability to paginate and sort through the results, but am having trouble determining the best approach such that the order of records is maintained. I am using PHP and Curl to send a rest request to the service.
The external API I am using is eventful (http://api.eventful.com/), and my MySQL database stores basically the same event information. I'd like to pull from both of these sources, sort, and enable pagination.
i.e
in this example, we have a LIMIT of 4, but some records may come from eventful and others from MySQL depending on the date. I would think you need to keep an offset of both the API and MySQL results, and decrement them by the number of records that are used in each page. However, I have no idea how to sort unless I pull all the records from both sources.
event name / date / source (E = eventful, M = MySQL)
| page_num 1 | page_num 2 | page_num 3 |
|:-----------:|------------:|:------------:|
| A|7/27|E | E|7/31|E | I|8/04|M |
| B|7/28|M | F|8/01|M | J|8/05|M |
| C|7/29|E | G|8/02|M | K|8/06|E |
| D|7/30|M | H|8/03|E | L|8/07|E |
How about pulling data from both sources, storing all in the database and then query that database using some php to paginate results.
If storing the data on your DB is not an option you have to merge and sort within PHP.
Here is an example (CodePad), using two unordered arrays - each one describing your data sources:
$mysql = array
(
array('name' => 'I', 'date' => '20110804'),
array('name' => 'J', 'date' => '20110805'),
array('name' => 'F', 'date' => '20110801'),
array('name' => 'D', 'date' => '20110730'),
array('name' => 'B', 'date' => '20110728'),
array('name' => 'G', 'date' => '20110802'),
);
$eventful = array
(
array('name' => 'L', 'date' => '20110807'),
array('name' => 'A', 'date' => '20110727'),
array('name' => 'E', 'date' => '20110731'),
array('name' => 'H', 'date' => '20110803'),
array('name' => 'K', 'date' => '20110806'),
array('name' => 'C', 'date' => '20110729'),
);
You'll want to select an equal amount of maximum events to display on each data source, and merge both arrays into a single multi-dimensional array, which we will then sort using array_multisort():
$dates = array();
$result = array_merge($mysql, $eventful);
foreach ($result as $key => $value)
{
$dates[$key] = $value['date'];
}
array_multisort($dates, SORT_ASC, $result);
The $result variable will then be sorted in ascending order:
Array
(
[0] => Array
(
[name] => A
[date] => 20110727
)
[1] => Array
(
[name] => B
[date] => 20110728
)
[2] => Array
(
[name] => C
[date] => 20110729
)
[3] => Array
(
[name] => D
[date] => 20110730
)
[4] => Array
(
[name] => E
[date] => 20110731
)
[5] => Array
(
[name] => F
[date] => 20110801
)
[6] => Array
(
[name] => G
[date] => 20110802
)
[7] => Array
(
[name] => H
[date] => 20110803
)
[8] => Array
(
[name] => I
[date] => 20110804
)
[9] => Array
(
[name] => J
[date] => 20110805
)
[10] => Array
(
[name] => K
[date] => 20110806
)
[11] => Array
(
[name] => L
[date] => 20110807
)
)
If you need descending order you can use the SORT_DESC constant instead.
To paginate this array you can just use array_chunk():
$result = array_chunk($result, 4); // 4 events per "page"
Which, in turn, produces an array with an added dimension:
Array
(
[0] => Array
(
[0] => Array
(
[name] => A
[date] => 20110727
)
[1] => Array
(
[name] => B
[date] => 20110728
)
[2] => Array
(
[name] => C
[date] => 20110729
)
[3] => Array
(
[name] => D
[date] => 20110730
)
)
[1] => Array
(
[0] => Array
(
[name] => E
[date] => 20110731
)
[1] => Array
(
[name] => F
[date] => 20110801
)
[2] => Array
(
[name] => G
[date] => 20110802
)
[3] => Array
(
[name] => H
[date] => 20110803
)
)
[2] => Array
(
[0] => Array
(
[name] => I
[date] => 20110804
)
[1] => Array
(
[name] => J
[date] => 20110805
)
[2] => Array
(
[name] => K
[date] => 20110806
)
[3] => Array
(
[name] => L
[date] => 20110807
)
)
)
Bare in mind that this is a lot less efficient than the typical database sort and limit, mostly because you have the load the whole data into memory, even those that you don't need for the active "page".
I'm not sure what amount of data you're expecting to process but array_multisort() performs reasonably well up to a couple thousand records (I've actually never used it for anything larger), if you're looking for further optimizations you can destroy the unneeded indexes of the chunked array or, use array_slice() and some arithmetic to fetch the four specific records that belong to a certain page.
Nonetheless, if you can optimize your selects (maybe with some business / date logic, not sure) you will probably make the whole sorting + chunk (or slice) process more CPU and memory friendly.